
###########################################################################
###########################################################################
## run_utils.pl
## Utilities for doing stuff. Requiring this file makes perl programs
## much simpler. Maybe.
###########################################################################
###########################################################################

###########################################################################
## Require and include files.
use POSIX ":sys_wait_h";

###########################################################################
###########################################################################
## Sub ct10. Returns YYYYMMDDHH at chghrs after yyyymmddhh, NO leap year.
###########################################################################
###########################################################################

sub ct10 {
    my($indate,$chghour) = @_;
    $hrsperyr = 365.*24.;
    $yyyy = substr($indate,0,4);
    $mm = substr($indate,4,2);
    $dd = substr($indate,6,2);
    $hh = substr($indate,8,2);
    $useyyyy = "1981";
    $chgdate = "$useyyyy"."$mm"."$dd"."$hh";
    $chgyyyy = $chghour/$hrsperyr;
    $chgyrs = int($chgyyyy);
    $chghrs = sprintf("%.0f",(($chgyyyy-$chgyrs)*$hrsperyr));
    $tmpdate = &changetime10($chgdate,$chghrs);
    $tmpyyyy = substr($tmpdate,0,4);
    $tmpmm = substr($tmpdate,4,2);
    $tmpdd = substr($tmpdate,6,2);
    $tmphh = substr($tmpdate,8,2);
    if ($tmpyyyy == 1982) { $addyrs = 1; }
    else { $addyrs = 0; }
    $tmpyyyy = $yyyy + $chgyrs + $addyrs;
    $timeout = "$tmpyyyy"."$tmpmm"."$tmpdd"."$tmphh";
    return $timeout;
}

###########################################################################
###########################################################################
## Sub td. Returns days and seconds difference, NO leap year.
###########################################################################
###########################################################################

sub td {
    my($indate1,$junk1,$indate2,$junk2) = @_;
    my ($ddif,$sdif)=0;
    my ($m);
    $hrsperyr = 365.*24.;
    $secsperday = 3600.*24.;
    $useyyyy = "1983";
    @dpm = ();
    @dpm = (0,31,28,31,30,31,30,31,31,30,31,30,31);

    $yyyy1 = substr($indate1,0,4);
    $mm1 = substr($indate1,4,2);
    $dd1 = substr($indate1,6,2);
    $hh1 = substr($indate1,8,2);
    $nd1 = 0;
    for ($m=1;$m<=($mm1-1);$m++) { $nd1 = $nd1 + $dpm[$m]; }
    $nd1 = $nd1 + $dd1 + ($hh1/24.);
    $fracyr1 = $yyyy1 + ($nd1/365.);
    
    $yyyy2 = substr($indate2,0,4);
    $mm2 = substr($indate2,4,2);
    $dd2 = substr($indate2,6,2);
    $hh2 = substr($indate2,8,2);
    $nd2 = 0;
    for ($m=1;$m<=($mm2-1);$m++) { $nd2 = $nd2 + $dpm[$m]; }
    $nd2 = $nd2 + $dd2 + ($hh2/24.);
    $fracyr2 = $yyyy2 + ($nd2/365.);

    $yrdiff = $fracyr2 - $fracyr1;
    $ddif = int($yrdiff*365.);
    $sdif = sprintf("%.0f",(($yrdiff*365) - $ddif) * $secsperday);
    return ($ddif,$sdif);
}

###########################################################################
###########################################################################
## Sub ds. Returns days since date2 of date1. No leap year.
###########################################################################
###########################################################################

sub ds {
    my($indate1,$indate2) = @_;
    my ($ddif,$sdif,$ds)=0;
    my ($m);
    $hrsperyr = 365.*24.;
    $secsperday = 3600.*24.;
    $useyyyy = "1983";
    @dpm = ();
    @dpm = (0,31,28,31,30,31,30,31,31,30,31,30,31);

    $yyyy1 = substr($indate1,0,4);
    $mm1 = substr($indate1,4,2);
    $dd1 = substr($indate1,6,2);
    $hh1 = substr($indate1,8,2);
    $nd1 = 0;
    for ($m=1;$m<=($mm1-1);$m++) { $nd1 = $nd1 + $dpm[$m]; }
    $nd1 = $nd1 + $dd1 + ($hh1/24.);
    $fracyr1 = $yyyy1 + ($nd1/365.);
    
    $yyyy2 = substr($indate2,0,4);
    $mm2 = substr($indate2,4,2);
    $dd2 = substr($indate2,6,2);
    $hh2 = substr($indate2,8,2);
    $nd2 = 0;
    for ($m=1;$m<=($mm2-1);$m++) { $nd2 = $nd2 + $dpm[$m]; }
    $nd2 = $nd2 + $dd2 + ($hh2/24.);
    $fracyr2 = $yyyy2 + ($nd2/365.);

    $yrdiff = $fracyr2 - $fracyr1;
    $ddif = int($yrdiff*365.);
    $sdif = sprintf("%.0f",(($yrdiff*365) - $ddif) * $secsperday);
    $df = $sdif/$secsperday;
    $ds = $ddif + $df;
    return ($ds);
}

###########################################################################
###########################################################################
## Sub ds1860. Returns number of days since 1860.
###########################################################################
###########################################################################

sub ds1860 {
    my($yyyymmddhh) = @_;
    my($yyyy,$mm,$dd,$hh);
    $yyyy = substr($yyyymmddhh,0,4);
    $mm = substr($yyyymmddhh,4,2);
    $dd = substr($yyyymmddhh,6,2);
    $hh = substr($yyyymmddhh,8,2);
    my($iyyyy,$imm,$idd,$ihh);
    my($iyyyymmddhh);
    my($y,$m,$d,$h);
    my($ds);
    my(@ndays);
    $iyyyymmddhh = 1860010100;
    $iyyyy = substr($iyyyymmddhh,0,4);
    $imm = substr($iyyyymmddhh,4,2);
    $idd = substr($iyyyymmddhh,6,2);
    $ihh = substr($iyyyymmddhh,8,2);
    @ndays = (0,31,28,31,30,31,30,31,31,30,31,30,31);
    $ds=0;
    for ($y=$iyyyy+1;$y<=$yyyy;$y++) { $ds = $ds + 365; }
    for ($m=0;$m<$mm;$m++) { $ds = $ds + $ndays[$m]; }
    $ds = $ds + $dd - 1;
    $ds = $ds + ($hh/24);    
    return("$ds");
}

###########################################################################
###########################################################################
## End of sub ds1860.
###########################################################################
###########################################################################


###########################################################################
###########################################################################
## Sub idx1860. Returns number of days since 1860.
###########################################################################
###########################################################################

sub idx1860 {
    my($yyyymmddhh,$iyyyymmddhh,$inc) = @_;
    my($yyyy,$mm,$dd,$hh);
    $yyyy = substr($yyyymmddhh,0,4);
    $mm = substr($yyyymmddhh,4,2);
    $dd = substr($yyyymmddhh,6,2);
    $hh = substr($yyyymmddhh,8,2);
    my($iyyyy,$imm,$idd,$ihh);
    my($y,$m,$d,$h);
    my($ds);
    my($idx);
    my(@ndays);
    $iyyyy = substr($iyyyymmddhh,0,4);
    $imm = substr($iyyyymmddhh,4,2);
    $idd = substr($iyyyymmddhh,6,2);
    $ihh = substr($iyyyymmddhh,8,2);
    @ndays = (0,31,28,31,30,31,30,31,31,30,31,30,31);
    $ds=0;
    for ($y=$iyyyy+1;$y<=$yyyy;$y++) { $ds = $ds + 365; }
    for ($m=0;$m<$mm;$m++) { $ds = $ds + $ndays[$m]; }
    $ds = $ds + $dd - 1;
    $ds = $ds + ($hh/24) - ($inc/24);
    $hs = 24 * $ds;
    $idx = ($hs / $inc);
    return("$idx");
}

###########################################################################
###########################################################################
## End of sub idx1860.
###########################################################################
###########################################################################


###########################################################################
###########################################################################
## Sub ds2006. Returns number of days since 1860.
###########################################################################
###########################################################################

sub ds2006 {
    my($yyyymmddhh) = @_;
    my($yyyy,$mm,$dd,$hh);
    $yyyy = substr($yyyymmddhh,0,4);
    $mm = substr($yyyymmddhh,4,2);
    $dd = substr($yyyymmddhh,6,2);
    $hh = substr($yyyymmddhh,8,2);
    my($iyyyy,$imm,$idd,$ihh);
    my($iyyyymmddhh);
    my($y,$m,$d,$h);
    my($ds);
    my(@ndays);
    $iyyyymmddhh = 2006010100;
    $iyyyy = substr($iyyyymmddhh,0,4);
    $imm = substr($iyyyymmddhh,4,2);
    $idd = substr($iyyyymmddhh,6,2);
    $ihh = substr($iyyyymmddhh,8,2);
    @ndays = (0,31,28,31,30,31,30,31,31,30,31,30,31);
    $ds=0;
    for ($y=$iyyyy+1;$y<=$yyyy;$y++) { $ds = $ds + 365; }
    for ($m=0;$m<$mm;$m++) { $ds = $ds + $ndays[$m]; }
    $ds = $ds + $dd - 1;
    $ds = $ds + ($hh/24);    
    return("$ds");
}

###########################################################################
###########################################################################
## End of sub ds2006.
###########################################################################
###########################################################################


###########################################################################
###########################################################################
## Sub idx2006. Returns number of days since 2006.
###########################################################################
###########################################################################

sub idx2006 {
    my($yyyymmddhh,$iyyyymmddhh,$inc) = @_;
    my($yyyy,$mm,$dd,$hh);
    $yyyy = substr($yyyymmddhh,0,4);
    $mm = substr($yyyymmddhh,4,2);
    $dd = substr($yyyymmddhh,6,2);
    $hh = substr($yyyymmddhh,8,2);
    my($iyyyy,$imm,$idd,$ihh);
    my($y,$m,$d,$h);
    my($ds);
    my($idx);
    my(@ndays);
    $iyyyy = substr($iyyyymmddhh,0,4);
    $imm = substr($iyyyymmddhh,4,2);
    $idd = substr($iyyyymmddhh,6,2);
    $ihh = substr($iyyyymmddhh,8,2);
    @ndays = (0,31,28,31,30,31,30,31,31,30,31,30,31);
    $ds=0;
    for ($y=$iyyyy+1;$y<=$yyyy;$y++) { $ds = $ds + 365; }
    for ($m=0;$m<$mm;$m++) { $ds = $ds + $ndays[$m]; }
    $ds = $ds + $dd - 1;
    $ds = $ds + ($hh/24) - ($inc/24);
    $hs = 24 * $ds;
    $idx = ($hs / $inc);
    return("$idx");
}

###########################################################################
###########################################################################
## End of sub idx2006.
###########################################################################
###########################################################################


###########################################################################
###########################################################################
## Sub check_news. Checks if I am news or not.
###########################################################################
###########################################################################
sub check_news(){
   my $me, $news;
   $itsme=1;
#   $itsme=0;
#   $me=`/sbin/ifconfig |/bin/grep eth0:0`;
#   if($me=~'eth0:0'){$itsme=1;}
}
###########################################################################
###########################################################################
## End of sub check_news.
###########################################################################
###########################################################################


###########################################################################
###########################################################################
## Sub checkftp. Checks to see if the file you want is there/big enough.
###########################################################################
###########################################################################
sub checkftp {

###########################################################################
## Set variables.
    my($server,$login,$password,$path,$file,$dir) = @_;
    my($size);
    my(@ftpcrap)=();
    my(@sizefields) = ();
    my($sizeline,$p);
    my($tries)=0;
    my($maxtries)=60;
    my($sleepsecs)=1;

###########################################################################
## Go to a directory to work in.
    chdir ("$dir");

###########################################################################
## Make an ftp command file then run the ftp process to get a listing.
    system ("rm -f $dir/ftpcoms.$file.$$");
    open (FTP,">$dir/ftpcoms.$file.$$");
    print FTP <<"END";
 open $server
 user $login $password
 cd $path
 binary
 dir $file
 quit
END
    close FTP;

###########################################################################
## Run the ftp listing in the background to make sure it doesn't hang up.
    system ("rm -f $dir/ftp.$file.$$.output");
    $com = "ftp -nv < $dir/ftpcoms.$file.$$ > $dir/ftp.$file.$$.output 2>&1 ";
    &bgrun($com,$sleepsecs,$maxtries);
    system ("rm -f $dir/ftpcoms.$file.$$");

###########################################################################
## Get the file size by parsing the ftp listing you just got.
    if ( -e "$dir/ftp.$file.$$.output" ) {
	open (IN,"<$dir/ftp.$file.$$.output");
	chomp (@ftpcrap = <IN>);
	close IN;
	system ("rm -f $dir/ftp.$file.$$.output");

	$sizeline = "";
	FTPOUTPUT : for ($p=0;$p<=$#ftpcrap;$p++) {
	    if ($ftpcrap[$p] =~ m/$file/g) {
		$sizeline = $ftpcrap[$p];
		last FTPOUTPUT;
	    }
	}
	$sizeline   =~ s/\s+/,/g;
	@sizefields = split(",",$sizeline);
	$size       = $sizefields[4];
    }
    else {
	$size = 0;
    }

###########################################################################
## Return the size of the file on the ftp server.
    return("$size");

}
###########################################################################
###########################################################################
## End of sub checkftp.
###########################################################################
###########################################################################


###########################################################################
###########################################################################
## Sub getftp. Gets the file you want.
###########################################################################
###########################################################################
sub getftp {

    my($dir,$name,$server,$login,$password,$path,$file) = @_;
    my($tries)=0;
    my($maxtries)=360;
    my($sleepsecs)=10;
    my($com)="";

###########################################################################
## Make an ftp command file.
    chdir ("$dir");
    system ("rm -f $dir/ftpcoms.$file.$$");
    open (FTP,">$dir/ftpcoms.$file.$$");
    print FTP <<"END";
 open $server
 user $login $password
 cd $path
 binary
 get $file $name
 quit
END
    close FTP;

###########################################################################
## Get the ftp file. Kill the job if it takes too long.
    system ("rm -f $dir/ftpout.$file.$$");
    $com = "ftp -nv < $dir/ftpcoms.$file.$$ > $dir/ftpout.$file.$$ 2>&1 ";
    &bgrun($com,$sleepsecs,$maxtries);
    system ("rm -f $dir/ftpout.$file.$$");
    system ("rm -f $dir/ftpcoms.$file.$$");

}
###########################################################################
###########################################################################
## End of sub getftp.
###########################################################################
###########################################################################


###########################################################################
###########################################################################
## Sub bgrun. Runs a job in the background and kills it if it takes 
## too long.
###########################################################################
###########################################################################
sub bgrun {
    my($com,$sleepsecs,$maxtries)=@_;
    my($pid,$tries,$kid);
    $pid = 0;
##########################################################################
##########################################################################
## Parse command and change redirects.
#    ($command,$args1)        = split ("<",$com);
#    ($stdin,$args2,$extra)   = split (">",$args1);
#    ($stdout,$args3)         = split ("2",$args2);
#    $com=$command;
#    close STDIN;
#    open (STDIN,"<$stdin");
#    close STDOUT;
#    open (STDOUT,">$stdout");
#    close STDERR;
#    open (STDERR,">&STDOUT");
##########################################################################
##########################################################################
    unless ($pid = fork) {
	exec "$com";
	exit;
    } else {
	$tries=0;
	do { 
	    $kid = waitpid($pid,&WNOHANG);
	    $tries++;
	    sleep $sleepsecs;
	    if ($tries>=$maxtries) {
##########################################################################
##########################################################################
## Kill the processes.
                kill -9,$pid;
                kill  9,$pid;
##########################################################################
##########################################################################
		$kid = waitpid($pid,0);
	    }
	} until (($kid == -1)||($kid == $pid));
    }
    return("1");
}
###########################################################################
###########################################################################
## End of sub bgrun.
###########################################################################
###########################################################################


###########################################################################
###########################################################################
## Sub getn12date. Returns the nearest 12h Z time given user cutoffs.
###########################################################################
###########################################################################
sub getn12date {

    my($zerocutoff,$twelvecutoff)=@_;
    my($date,$hour,$tdate,$rundate);
    $date = substr(&time_increment(time,i4,0,0,yy,"utc"),0,10);
    $hour = sprintf("%2.2d",substr($date,8,2));
    if ($hour < $zerocutoff) {
        $tdate = substr(&changetime10($date,-12),0,8);
        $rundate = "$tdate"."12";
    }
    elsif ($hour < $twelvecutoff) {
        $tdate = substr($date,0,8);
        $rundate = "$tdate"."00";
    }
    else {
        $tdate = substr($date,0,8);
        $rundate = "$tdate"."12";
    }
    return($rundate);
}
###########################################################################
###########################################################################
## End of sub getn12date.
###########################################################################
###########################################################################


###########################################################################
###########################################################################
## Sub prepripinput. Prep's a rip input file.
###########################################################################
###########################################################################
sub prepripinput {

    my($templates,$dir,$vrbl,$domain,$h,$mname) = @_;
    $hours       = "$h";
    my($hh)      = sprintf("%2.2d",$h);
    my($hour)    = sprintf("%4.1f,",$h);
    my($outfile) = "$dir/$vrbl.d$domain.$hh.in";
    my($infile)  = "$templates/$vrbl" . "_d$domain.in";
    my(@indata)  = ();

    open (IN,"<$infile");
    chomp(@indata=<IN>);
    close IN;

    system ("rm -f $outfile");
    open (OUT,">$outfile");
    for ($i=0;$i<=$#indata;$i++) {
	$indata[$i] =~ s/#mname#/$mname/g;
	$indata[$i] =~ s/#domain#/$domain/g;
	$indata[$i] =~ s/#hour#/$hour/g;
	$indata[$i] =~ s/#hours#/$hours/g;
	print OUT ("$indata[$i]\n");
    }
    close OUT;

    return(1);

}
###########################################################################
###########################################################################
## End of sub prepripinput.
###########################################################################
###########################################################################



###########################################################################
###########################################################################
## Sub twoxtimes. Makes a single xtimes file from two.
###########################################################################
###########################################################################
sub multixtimes {

    my($indir,$dir,$domain,$shh,$ehh,$inc) = @_;
    if ($shh<0) { $shh=0; }
    $hh      = sprintf("%2.2d",$hh);
    $phh     = sprintf("%2.2d,",$phh);
    $outfile = "$dir/wrfout.xtimes";
    $nhrs    = (($ehh-$shh)/$inc)+1;
    
    system ("rm -f $outfile");
    open (OUT,">$outfile");
    printf OUT ("%13d\n",$nhrs);
    for ($i=$shh;$i<=$ehh;$i=$i+$inc) {
	$hh = sprintf("%2.2d",$i);
	$infile = "$indir/wrfout_domain${domain}.$hh.xtimes";
	@indata = ();
	open (IN,"<$infile");
	chomp(@indata=<IN>);
	close IN;
	for ($j=1;$j<=$#indata;$j++) {
	    print OUT ("$indata[$j]\n");
	}
    }
    close OUT;
    return(1);

}
###########################################################################
###########################################################################
## End of sub twoxtimes.
###########################################################################
###########################################################################


###########################################################################
###########################################################################
## End of run_utils.pl.
###########################################################################
###########################################################################
1;

# Perl Time Libraries version 1.0  September 3, 1999
# Compiled or written by David Ovens, Univ. of Washington 
#                        (ovens@atmos.washington.edu)
# Permission to use and distribute these is granted in compliance with
# the GNU licensing agreement.  Let me know of any changes.
#------------------Perl Subroutine time_increment -------------------------
sub time_increment {
    my ($timein,$formatin,$incday,$incsec,$formatout,$timezone,$option) = @_;
    my ($timeout);
    local ($utc_local) = 8; # UTC is 8 hours later than Local Standard Time
#**********************************************************************c
#     time_increment will take various time inputs in UTC/GMT or local time
#         i4time
#         yyyymmddhhmmss
#         Julianday nseconds (space-separated)
#       add the requested number of days and/or seconds and return the
#       time in any of those forms or additional user-specified forms.    
#
#     INPUTS:
#       timein          variable      i4time [i4],
#                                     yyyymmddhhmmss [yy],
#                                     "Julianday nsec" [js],
#                                     "YYYY.MM.DD.HH:NN:SS" [yd],
#                                     "YYYYJJJHHNNSS" [yj],
#                                     "[YYYYMMDD][HH][:NN:SS]" [ye],
#                                     "YYYY-MM-DD HH:NN:SS" [ql]
#       formatin        CHARACTER     "i4",
#                                     "yy",
#                                     "js",
#                                     "yd",
#                                     "yj",
#                                     "ye",
#                                     "ql"
#       incday          INTEGER       Number of days to increment.
#       incsec          INTEGER       Number of seconds to increment.
#       formatout       CHARACTER     "i4",
#                                     "yy",
#                                     "js",
#                                     "yd",
#                                     "yj",
#                                     "ql"
#                                     "unix" = "day mon dd hh:nn:ss tzone year"
#                                       may use &quick_unix_time
#         NOTE:  yy alone is equivalent to yyyymmddhhnnss
#         Substitution will occur if formatout does not exactly match one 
#         of the 3 standards mentioned above.  Substitutions are:
#             year or yyyy   --> complete year (however many digits are needed)
#             yy             --> last 2 digits of year
#             mm             --> month as 2 digits
#             dd             --> day of month as 2 digits
#             d1             --> day of month as 1 or 2 digits
#             hh             --> hour as 2 digits
#             h12            --> nearest 12-hour time (00 or 12)
#             h1             --> hour as 1 or 2 digits, whichever fits
#             hN             --> nearest N-hour time (00 N 2N 3N ..)
#             nn             --> minute as 2 digits
#             ss             --> second as 2 digits
#             jjj            --> 3-digit day of the year (001 to 365 or 366)
#             jj             --> Astonomical Julian day (day 0 = 1/1/-4713)
#             jsec           --> number of seconds into Julian day
#             weekday        --> long name of day of week
#             day            --> short name of day of week
#             month          --> long name of month
#             mon            --> short name of month
#             ampm           --> indicate am/pm and use hours <= 12
#             tzone          --> 3-character time zone (DEFAULT is UTC,
#                                 unless optional timezone input is used)
#     OPTIONAL INPUTS:
#       timezone       CHARACTER   "local-UTC","UTC-local","local","UTC"
#                                   (DEFAULT is UTC)
#                                  The "local-UTC" and "UTC-local" timezone
#                                    choices are preferred.  They correctly 
#                                    convert local/UTC INPUT times to 
#                                    UTC/local OUTPUT times.  NOTE: that a
#                                    UTC-local conversion followed by a 
#                                    local-UTC conversion will be one hour off
#                                    between 1 and 2 AM local time on the date
#                                    of the October changeover.
#       NOTE                       i4 times are ALWAYS in UTC, gmtime() and
#                                    localtime() give appropriate values based
#                                    on this i4 time.
#                                  When "local" is chosen, the input time is
#                                    assumed to be the same time zone as 
#                                    timezone, though i4times will be 
#                                    automatically converted from their native
#                                    UTC values.  In other words, only cases
#                                    with formatin "i4" will do any time zone
#                                    conversions, others just assume inputs
#                                    and outputs are in the same time zone.
#       CAUTION                    Using "local" will give you DAYLIGHT time
#                                    during the 1 am to 2 am period of the
#                                    October changeover, since the function is
#                                    multivalued then.  Safer to use UTC-local.
#                                  Also, unless you are doing "UTC-local" or
#                                    "local-UTC", a time increment across a 
#                                    time zone switch behaves as though no 
#                                    switch occurs for all formatins EXCEPT 
#                                    "i4" which would have a one-hour shift in
#                                    one direction.
#       option          CHARACTER    "split" will split any output format 
#                                     containing a ${date}[._]${suffix} into
#                                     ${date},${suffix}.  This is useful for
#                                     full-valued master_pattern_file entries.
#     OUTPUT:
#       timeout         variable      Output time in chosen format.
#                                     -1 indicates an error. 
# Modifications:
#                D. Ovens (1/20/1999) Added upper-case to output format
#                                     so master_pattern_file can be used.
#                D. Ovens (4/7/1999) Changed output of yyyy or year from a
#                                     a 4-digit year to the complete year.
#                D. Ovens (4/20/1999) Added "yd" formats.
#                D. Ovens (5/3/1999) Added h12 (nearest 12-hour time) 
#                                     to output formats.
#                D. Ovens (8/26/1999) Added translation for (now,i4) 
#                                      formats for ($timein,$formatin).
#                                     Added yj input/output and jjj output 
#                                      formats.
#                D. Ovens (1/13/2000) Fixed it so a formatout "i4" with a
#                       timezone of "local-utc" will work.  The "i4" output
#                       still is not recommended with "local" or "utc-local".
#                D. Ovens (3/13/2000) Added hN (nearest N-hour time, where N 
#                                      is an integer) to output formats.
#                D. Ovens (1/3/2001) Fixed jjj output (day 4 now = 004).
#                D. Ovens (2/4/2001) Added form "ye" for expanded times.
#                D. Ovens (10/4/2001) Added form "ql" for mySQL datetime.
#                D. Ovens (10/10/2001) Changed "ye" so that a single digit
#                       expands to two:  1 means 01 not 1, 11, or 21.
#                D. Ovens (1/10/2002) Added form "unix" for formatout.
#                D. Ovens (4/4/2002) Added forms "h1", "d1", and "ampm".
#**********************************************************************c
    my($yyyymmddhhmmss, $julianday, $nseconds, $ier,$newyear,
	  @months,@days,$year,$yy,$mm,$dd,$hh,$nn,$ss,$length,
	  $h12,$hx,$dot_location,$underscore_location,$time,$suffix,
	  $jday1,$juliandayofyear,$jjj,$incr,$count,$thisday,$inday,
          $h1,$d1);

#
#   Convert everything to Julianday nseconds format for calculations.
#
    if ($formatout eq "unix" || $formatout eq "UNIX") {
	$formatout = "day mon dd hh:nn:ss tzone year";
	$timezone = "utc-local" if ($timezone eq "");
	if ($formatin eq "i4") {
	    if ($timein =~ /^(NOW|now)/) {
		$timein = time;
	    }
	    if ($timein < 2147483647 && $timezone =~ /(utc-local|UTC-LOCAL)/) {
		return &quick_unix_time($timein);
	    }
	}
    }
    unless ($timezone) {
	$timezone = "UTC";
    }
    if ($formatin =~ /(i4|I4)/) {
	if ($timein =~ /^(NOW|now)/) {
	    $timein = time;
	}
	if ($timezone =~ /^(local|LOCAL)-(utc|UTC)$/) {
	    $timezone = "UTC";
	}
	($julianday,$nseconds,$ier) = &jdaysec_i4time($timein);
    } elsif ($formatin =~ /(yy|YY)/) {
	$length = length($timein);
	$year = substr($timein,0,($length-10));
	$mm   = substr($timein,($length-10),2);
	$dd   = substr($timein,($length-8),2);
	$hh   = substr($timein,($length-6),2); 
	$nn   = substr($timein,($length-4),2);
	$ss   = substr($timein,($length-2),2);
	($julianday,$nseconds,$ier) = &jdaysec_yyyymmddhhmmss($year,$mm,$dd,$hh,$nn,$ss);
    } elsif ($formatin =~ /(yj|YJ)/) { # Y*JJJHHNNSS
	$length = length($timein);
	$year = substr($timein,0,($length-9));
	$jjj  = substr($timein,($length-9),3);
	$hh   = substr($timein,($length-6),2); 
	$nn   = substr($timein,($length-4),2);
	$ss   = substr($timein,($length-2),2);
	($julianday,$nseconds,$ier) = &jdaysec_yyyyjjjhhmmss($year,$jjj,$hh,$nn,$ss);
    } elsif ($formatin =~ /(yd|YD|ql|QL)/) {
	$length = length($timein);
	$year = substr($timein,0,($length-15));
	$mm   = substr($timein,($length-14),2);
	$dd   = substr($timein,($length-11),2);
	$hh   = substr($timein,($length-8),2); 
	$nn   = substr($timein,($length-5),2);
	$ss   = substr($timein,($length-2),2);
	($julianday,$nseconds,$ier) = &jdaysec_yyyymmddhhmmss($year,$mm,$dd,$hh,$nn,$ss);
    } elsif ($formatin =~ /(ye|YE)/) {
	($julianday,$nseconds,$ier) = &jdaysec_i4time(time);
	$yyyymmddhhnnss = &yyyymmddhhmmss_jdaysec($julianday,$nseconds);
	if ($timein ne "") {
	    $timein =~ s/^(\d+)?:?(\d\d)?:?(\d\d)?/$1$2$3/;
	    $ss = $3;
	    $nn = $2;
	    $dd = substr($1,-2);
	    if (length($1) == 1) {
		##
		## expand a single hour, n, to 0n
		$timein = "0$timein";
	    }
	    if ($ss ne "") {
		$incr = 1;
	    } elsif ($nn ne "") {
		$nseconds = $nseconds - ($nseconds%60);
		$incr = 60;
		$timein = "${timein}00";
	    } else {
		$nseconds = $nseconds - ($nseconds%3600);
		$incr = 3600;
		$timein = "${timein}0000";
	    }
	    $length = length($timein);
	    if ($length > 2 && $incr <= 1) {
		$nseconds = $nseconds - ($nseconds%60) + $ss;
		$incr = 60;
	    }
	    if ($length > 4 && $incr <= 60) {
		$nseconds = $nseconds - ($nseconds%3600) + $nn*60 + $ss;
		$incr = 3600;
	    }
	    if ($length > 6 && $incr <= 3600) {
		$nseconds = $nseconds - ($nseconds%86400) + $dd*3600 + $nn*60 + $ss;
		$inday   = substr($timein,0,(length($timein)-6));
		$thisday = substr($yyyymmddhhnnss,0,(length($yyyymmddhhnnss)-6));
		$thisday = substr($thisday,(-1*length($inday)));
		## is that complicated enough for you?
#	    print "thisday = $thisday  inday = $inday\n";
		if ($thisday ne $inday) {
		    $incr = 86400;
		}
	    }
	    if ($length < 14) {
		$count = 0;
		if ($length >= 12) {
		    ##
		    ## this allows future times but only in the current year
		    $year = substr($yyyymmddhhnnss,0,(length($yyyymmddhhnnss)-10));
		    $newyear = substr($yyyymmddhhnnss,0,(14-$length)) . substr($timein,0,($length-10));
		    until ($newyear <= $year &&
			   substr($newyear,(14-$length),($length-10)) eq substr($timein,0,($length-10)) ) {
			$newyear--;
		    }
		    $yyyymmddhhnnss = "$newyear" . substr($timein,($length-10),10);
		} else {
		    until ( substr($yyyymmddhhnnss,(-1*$length)) eq $timein) {
			$yyyymmddhhnnss = &time_increment("$julianday $nseconds",js,0,(-$incr*$count++),yy);
#		print "$yyyymmddhhnnss $incr $count    $timein\n";
			if ($count > 200) {
			    print STDERR "ERROR in subroutine time_increment of date-lib.pl
Could not match $timein after 200 ${incr}-second time changes.\n";
			    return -1;
			}
		    }
		}
#	    print "got time in $count attempts\n";
	    } else {
#	    print "had sufficient info\n";
		$yyyymmddhhnnss = $timein;
	    }
	}
	$length = length($yyyymmddhhnnss);
	$year = substr($yyyymmddhhnnss,0,($length-10));
	$mm   = substr($yyyymmddhhnnss,($length-10),2);
	$dd   = substr($yyyymmddhhnnss,($length-8),2);
	$hh   = substr($yyyymmddhhnnss,($length-6),2); 
	$nn   = substr($yyyymmddhhnnss,($length-4),2);
	$ss   = substr($yyyymmddhhnnss,($length-2),2);
	($julianday,$nseconds,$ier) = &jdaysec_yyyymmddhhmmss($year,$mm,$dd,$hh,$nn,$ss);
    } elsif ($formatin =~ /(j(ulianday)?s|JS)/) {
	($julianday,$nseconds) = split(' ',$timein);
    }
#
#   Do the time increment.
#
    ($julianday,$nseconds) = &jdaysec_increment($julianday,$nseconds,$incday,$incsec);
#
#   Convert to output format.
#
    if ($formatout eq "i4" || $formatout eq "I4") {
	if ($timezone ne "UTC") {
	    ($julianday,$nseconds,$timezone) = &timezone_shift($julianday,$nseconds,$utc_local,$timezone);
	}
	$timeout = &i4time_jdaysec($julianday,$nseconds);
    } elsif ($formatout eq "js" || $formatout eq "JS") {
	if ($timezone ne "UTC") {
	    ($julianday,$nseconds,$timezone) = &timezone_shift($julianday,$nseconds,$utc_local,$timezone);
	}
	$timeout = "$julianday $nseconds";
    } elsif ($formatout =~ /^(yy|YY)(yymmddhhmmss|YYMMDDHHMMSS|yymmddhhnnss|YYMMDDHHNNSS)?$/) {
	if ($timezone ne "UTC") {
	    ($julianday,$nseconds,$timezone) = &timezone_shift($julianday,$nseconds,$utc_local,$timezone);
	}
	$timeout = &yyyymmddhhmmss_jdaysec($julianday,$nseconds);
    } elsif ($formatout =~ /^(yj|YJ)(yyyyjjjhhmmss|YYYYJJJHHMMSS|yyyyjjjhhnnss|YYYYJJJHHNNSS)?$/) {
	if ($timezone ne "UTC") {
	    ($julianday,$nseconds,$timezone) = &timezone_shift($julianday,$nseconds,$utc_local,$timezone);
	}
	$timeout = &yyyyjjjhhmmss_jdaysec($julianday,$nseconds);
    } elsif ($formatout =~ /^(yd|YD)$/) {
	if ($timezone ne "UTC") {
	    ($julianday,$nseconds,$timezone) = &timezone_shift($julianday,$nseconds,$utc_local,$timezone);
	}
	$yyyymmddhhmmss = &yyyymmddhhmmss_jdaysec($julianday,$nseconds);
	$length = length($yyyymmddhhmmss);
	$year = substr($yyyymmddhhmmss,0,($length-10));
	$mm   = substr($yyyymmddhhmmss,($length-10),2);
	$dd   = substr($yyyymmddhhmmss,($length-8),2);
	$hh   = substr($yyyymmddhhmmss,($length-6),2); 
	$nn   = substr($yyyymmddhhmmss,($length-4),2);
	$ss   = substr($yyyymmddhhmmss,($length-2),2);
	$timeout = sprintf("%s.%2.2d.%2.2d.%2.2d:%2.2d:%2.2d",
			   $year, $mm, $dd, $hh, $nn, $ss);
    } elsif ($formatout =~ /^(ql|QL)$/) {
	if ($timezone ne "UTC") {
	    ($julianday,$nseconds,$timezone) = &timezone_shift($julianday,$nseconds,$utc_local,$timezone);
	}
	$yyyymmddhhmmss = &yyyymmddhhmmss_jdaysec($julianday,$nseconds);
	$length = length($yyyymmddhhmmss);
	$year = substr($yyyymmddhhmmss,0,($length-10));
	$mm   = substr($yyyymmddhhmmss,($length-10),2);
	$dd   = substr($yyyymmddhhmmss,($length-8),2);
	$hh   = substr($yyyymmddhhmmss,($length-6),2); 
	$nn   = substr($yyyymmddhhmmss,($length-4),2);
	$ss   = substr($yyyymmddhhmmss,($length-2),2);
	$timeout = sprintf("%s-%2.2d-%2.2d %2.2d:%2.2d:%2.2d",
			   $year, $mm, $dd, $hh, $nn, $ss);
    } elsif ($formatout eq "YYYYMMDDHH" || $formatout eq "yyyymmddhh") {
	if ($timezone ne "UTC") {
	    ($julianday,$nseconds,$timezone) = &timezone_shift($julianday,$nseconds,$utc_local,$timezone);
	}
	$timeout = &yyyymmddhhmmss_jdaysec($julianday,$nseconds);
	$timeout = substr($timeout,0,(length($timeout)-4));
    } else {
	if ($timezone ne "UTC") {
	    ($julianday,$nseconds,$timezone) = &timezone_shift($julianday,$nseconds,$utc_local,$timezone);
	}
	@months = ("", "January", "February", "March", "April", "May", "June",
		   "July", "August", "September", "October", "November", "December");
	@days = ("Sunday", "Monday", "Tuesday", "Wednesday", "Thursday",
		 "Friday", "Saturday");
	$yyyymmddhhmmss = &yyyymmddhhmmss_jdaysec($julianday,$nseconds);
	$length = length($yyyymmddhhmmss);
	$year = substr($yyyymmddhhmmss,0,($length-10));
	$yy   = substr($year,(length($year)-2),2);
	$mm   = substr($yyyymmddhhmmss,($length-10),2);
	$dd   = substr($yyyymmddhhmmss,($length-8),2);
	$d1   = $dd*1;
	$hh   = substr($yyyymmddhhmmss,($length-6),2);
	$nn   = substr($yyyymmddhhmmss,($length-4),2);
	$ss   = substr($yyyymmddhhmmss,($length-2),2);
	$h12  = sprintf("%2.2d",($hh - $hh % 12));
	$timeout = $formatout;
	$timeout =~ s/(yyyy|YYYY|year|YEAR)/$year/g;
	$timeout =~ s/(yy|YY)/$yy/g;
	$timeout =~ s/(mm|MM)/$mm/g;
	$timeout =~ s/(dd|DD)/$dd/g;
	$timeout =~ s/(d1|D1)/$d1/g;
	if ($timeout =~ /(ampm|AMPM)/) {
	    if ($hh eq "00") {
		$hh = $h12 = 12;
		$timeout =~ s/ampm/am/g;
		$timeout =~ s/AMPM/AM/g;
	    } elsif ($hh eq "12") {
		$timeout =~ s/ampm/pm/g;
		$timeout =~ s/AMPM/PM/g;
	    } elsif ($hh < 12) {
		$timeout =~ s/ampm/am/g;
		$timeout =~ s/AMPM/AM/g;
	    } else {
		$hh -= 12;
		$h12 -= 12;
		$hh = "0$hh" if ($hh < 10);
		$h12 = "0$h12" if ($h12 < 10);
		$timeout =~ s/ampm/pm/g;
		$timeout =~ s/AMPM/PM/g;
	    }
	}
	$timeout =~ s/(hh|HH)/$hh/g;
	$timeout =~ s/(h12|H12)/$h12/g;
	$h1      = $hh*1;
	$timeout =~ s/(h1|H1)/$h1/g;
	if ($timeout =~ /(h|H)(\d{1,2})/) {
	    $hx = sprintf("%2.2d",($hh - $hh % $2));
	    $timeout =~ s/(h\d{1,2}|H\d{1,2})/$hx/g;
	}
	$timeout =~ s/(nn|NN)/$nn/g;
	$timeout =~ s/(ss|SS)/$ss/g;
	if ($timeout =~ /(jjj|JJJ)/) {
	    $jday1 = &julday_jjjyyyy(1,$year);
	    $juliandayofyear = $julianday - $jday1 + 1;
	    $juliandayofyear = sprintf "%3.3d",$juliandayofyear;
	    $timeout =~ s/(jjj|JJJ)/$juliandayofyear/g;
	}
	$timeout =~ s/(jj|JJ)/$julianday/g;
	$timeout =~ s/(tzone|TZONE)/$timezone/g;
	$timeout =~ s/(jsec|JSEC)/$nseconds/g;
	$timeout =~ s/(month|MONTH)/$months[$mm]/g;
	$timeout =~ s/(mon|MON)/substr($months[$mm],0,3)/e;
	if ($timeout =~ /(weekday|WEEKDAY)/) {
	    $timeout =~ s/(weekday|WEEKDAY)/$days[(($julianday+1)%7)]/;
	} elsif ($timeout =~ /(day|DAY)/) {
	    $timeout =~ s/(day|DAY)/substr($days[(($julianday+1)%7)],0,3)/e;
	}
##      now split time and suffix if requested
	if ($option eq "split") {
	    $dot_location = index($timeout,'.');
	    $underscore_location = index($timeout,'_');
	    if ($underscore_location > $dot_location) {
		if ($dot_location > 0) {
		    $time   = substr($timeout,0,$dot_location);
		    $suffix = substr($timeout,$dot_location); # from there to the end
		} else {
		    $time   = substr($timeout,0,$underscore_location);
		    $suffix = substr($timeout,$underscore_location); # from there to the end
		}
	    } elsif ($dot_location > $underscore_location) {
		if ($underscore_location > 0) {
		    $time   = substr($timeout,0,$underscore_location);
		    $suffix = substr($timeout,$underscore_location); # from there to the end
		} else {
		    $time   = substr($timeout,0,$dot_location);
		    $suffix = substr($timeout,$dot_location); # from there to the end
		}
	    } elsif ($dot_location == $underscore_location) {
		if ($dot_location > 0) {
		    print STDERR "ERROR in $0: date match does not make sense
$timeout has . and _ located at $dot_location and $underscore_location!\n";
		    exit 1;
		}
		$time = $timeout;
	    } # end of underscore and dot location checks
	    $timeout = join(',',$time,$suffix);
	} # end of option split
	$timeout =~ s/\\//g;
    }
    unless ($timeout) { $timeout = -1; }
    if ($ier) { $timeout = -1; }
    return $timeout;
} # end of subroutine time_increment

#------------------Perl Subroutine time_difference -------------------------
sub time_difference {
    my ($time1in,$format1in,$time2in,$format2in) = @_;
    my ($daydiff,$secdiff);
#**********************************************************************c
#     time_difference will take various time inputs in UTC/GMT for 2 
#       input times (time2 is assumed to be later than time1)
#         i4time
#         yyyymmddhhmmss
#         Julianday nseconds (space-separated)
#       and calculate the number of days and seconds between them
#
#     INPUTS:
#       time1in         variable      i4time,yyyymmddhhmmss,"Julianday nsec",
#                                       "YYYY.MM.DD.HH:NN:SS"
#       format1in       CHARACTER     "i4",  "yy", "js", "yd", "ql"
#       time2in         variable      i4time,yyyymmddhhmmss,"Julianday nsec",
#                                       "YYYY.MM.DD.HH:NN:SS"
#       format2in       CHARACTER     "i4",  "yy", "js", "yd", "ql"
#     OUTPUTS:
#       daydiff         integer       Number of days difference.
#                                     -1 indicates an error. 
#       secdiff         integer       Number of additional seconds separating 
#                                      time 2 from time 1.
#                                      
#  Modifications:
#     D. Ovens (4/7/1999) Changed yy input format to accept any length year.
#     D. Ovens (4/20/1999) Added yd formats.
#     D. Ovens (10/4/2001) Added ql format for mySQL datetime.
#**********************************************************************c
    my($julianday1, $nseconds1, $julianday2, $nseconds2, $ier,
	  $year, $mm, $dd, $hh, $nn, $ss, $length);
#
#   Convert everything to Julianday nseconds format for calculations.
#
    if ($format1in =~ /(i4|I4)/) {
	($julianday1,$nseconds1,$ier) = &jdaysec_i4time($time1in);
    } elsif ($format1in =~ /(yy|YY)/) {
	$length = length($time1in);
	$year = substr($time1in,0,($length-10));
	$mm   = substr($time1in,($length-10),2);
	$dd   = substr($time1in,($length-8),2);
	$hh   = substr($time1in,($length-6),2); 
	$nn   = substr($time1in,($length-4),2);
	$ss   = substr($time1in,($length-2),2);
	($julianday1,$nseconds1,$ier) = &jdaysec_yyyymmddhhmmss($year,$mm,$dd,$hh,$nn,$ss);
    } elsif ($format1in =~ /(yd|YD|ql|QL)/) {
	$length = length($time1in);
	$year = substr($time1in,0,($length-15));
	$mm   = substr($time1in,($length-14),2);
	$dd   = substr($time1in,($length-11),2);
	$hh   = substr($time1in,($length-8),2); 
	$nn   = substr($time1in,($length-5),2);
	$ss   = substr($time1in,($length-2),2);
	($julianday1,$nseconds1,$ier) = &jdaysec_yyyymmddhhmmss($year,$mm,$dd,$hh,$nn,$ss);
    } elsif ($format1in =~ /(j(ulianday)?s|JS)/) {
	($julianday1,$nseconds1) = split(' ',$time1in);
    }
    if ($format2in =~ /(i4|I4)/) {
	($julianday2,$nseconds2,$ier) = &jdaysec_i4time($time2in);
    } elsif ($format2in =~ /(yy|YY)/) {
	$length = length($time2in);
	$year = substr($time2in,0,($length-10));
	$mm   = substr($time2in,($length-10),2);
	$dd   = substr($time2in,($length-8),2);
	$hh   = substr($time2in,($length-6),2); 
	$nn   = substr($time2in,($length-4),2);
	$ss   = substr($time2in,($length-2),2);
	($julianday2,$nseconds2,$ier) = &jdaysec_yyyymmddhhmmss($year,$mm,$dd,$hh,$nn,$ss);
    } elsif ($format2in =~ /(yd|YD|ql|QL)/) {
	$length = length($time2in);
	$year = substr($time2in,0,($length-15));
	$mm   = substr($time2in,($length-14),2);
	$dd   = substr($time2in,($length-11),2);
	$hh   = substr($time2in,($length-8),2); 
	$nn   = substr($time2in,($length-5),2);
	$ss   = substr($time2in,($length-2),2);
	($julianday2,$nseconds2,$ier) = &jdaysec_yyyymmddhhmmss($year,$mm,$dd,$hh,$nn,$ss);
    } elsif ($format2in =~ /(j(ulianday)?s|JS)/) {
	($julianday2,$nseconds2) = split(' ',$time2in);
    }
#
#   Calculate the time difference.
#
    $daydiff = $julianday2 - $julianday1;
    $secdiff = $nseconds2 - $nseconds1;
    if ($daydiff > 0) { # we don't want negative seconds
	while ($secdiff >= 86400) {
	    $secdiff = $secdiff - 86400;
	    $daydiff = $daydiff + 1;
	}
	while ($secdiff < 0) {
	    $secdiff = $secdiff + 86400;
	    $daydiff = $daydiff - 1;
	}
    } elsif ($daydiff < 0) { # we don't want positive seconds
	while ($secdiff <= -86400) {
	    $secdiff = $secdiff + 86400;
	    $daydiff = $daydiff - 1;
	}
	while ($secdiff > 0) {
	    $secdiff = $secdiff - 86400;
	    $daydiff = $daydiff + 1;
	}
    } # else same day and seconds can be positive or negative
	
    return ($daydiff,$secdiff);
} # end of subroutine time_difference

#------------------Perl Subroutine jdaysec_yyyymmddhhmmss -----------------
sub jdaysec_yyyymmddhhmmss {
    my($year, $month, $day, $hour, $minute, $second) = @_;
    my($julianday, $nseconds, $ier);
    my(@ndays);
#**********************************************************************c
#     jdaysec_yyyymmddhhmmss returns the UTC/GMT Julian Day and number 
#       of seconds since midnight given 6 integers containing year,
#       month, day, hour, minute, second.
#
#
#     INPUTS:
#       year            INTEGER       FULL YEAR ONLY
#       month           INTEGER       1 to 12
#       day             INTEGER       1 to 31
#       hour            INTEGER       0 to 23
#       minute          INTEGER       0 to 59
#       second          INTEGER       0 to 59
#     OUTPUTS:
#       julianday       INTEGER       Full julian day.
#       nseconds        INTEGER       Number of seconds since midnight
#       ier             INTEGER       0 if successful, 1 if failure
#**********************************************************************c
    @ndays = (0,31,29,31,30,31,30,31,31,30,31,30,31);
    $nseconds = 0;
    $ier    = 0;

    if ($month < 1 || $month > 12 ||
	$day < 1 || $day > $ndays[$month] ||
	$hour < 0 || $hour > 23 ||
	$minute < 0 || $minute > 59 ||
	$second < 0 || $second > 59) {
# return error code.
#
	$ier = 1;
	print STDERR "error in jdaysec_yyyymmddhhmmss for $year.$month.$day.$hour:$minute:$second\n";
	print STDERR "please use a valid date\n";
    }

    $julianday = &julday_mmddyyyy($month,$day,$year);
    $nseconds = ($hour * 3600) + ($minute * 60) + $second;

    return ($julianday, $nseconds, $ier);
} # end of jdaysec_yyyymmddhhmmss

#------------------Perl Subroutine jdaysec_yyyyjjjhhmmss -----------------
sub jdaysec_yyyyjjjhhmmss {
    my($year, $jjj, $hour, $minute, $second) = @_;
    my($julianday, $nseconds, $ier);
    my(@ndays);
#**********************************************************************c
#     jdaysec_yyyyjjjhhmmss returns the UTC/GMT Julian Day and number 
#       of seconds since midnight given 5 integers containing year,
#       day of year, hour, minute, second.
#
#
#     INPUTS:
#       year            INTEGER       FULL YEAR ONLY
#       jjj             INTEGER       1 to 366
#       hour            INTEGER       0 to 23
#       minute          INTEGER       0 to 59
#       second          INTEGER       0 to 59
#     OUTPUTS:
#       julianday       INTEGER       Full julian day.
#       nseconds        INTEGER       Number of seconds since midnight
#       ier             INTEGER       0 if successful, 1 if failure
#**********************************************************************c
    $nseconds = 0;
    $ier    = 0;

    if ($jjj < 1 || $jjj > 366 ||
	$hour < 0 || $hour > 23 ||
	$minute < 0 || $minute > 59 ||
	$second < 0 || $second > 59) {
# return error code.
#
	$ier = 1;
	print STDERR "error in jdaysec_yyyyjjjhhmmss for $year.$jjj.$hour:$minute:$second\n";
	print STDERR "please use a valid date\n";
    }

    $julianday = &julday_jjjyyyy($jjj,$year);
    $nseconds = ($hour * 3600) + ($minute * 60) + $second;

    return ($julianday, $nseconds, $ier);
} # end of jdaysec_yyyyjjjhhmmss

#------------------Perl Subroutine yyyymmddhhmmss_jdaysec -----------------
sub yyyymmddhhmmss_jdaysec {
    my ($julianday,$nseconds) = @_;
    my ($yyyymmddhhmmss);
    my ($month, $day, $year, $hour, $minute, $second);
#**********************************************************************c
#     yyyymmddhhmmss_jdaysec returns the time as YYYYMMDDHHMMSS (a 14
#       character string) given an appropriate Julidan Day and number
#       of seconds since midnight
#
#     INPUTS:
#       julianday       INTEGER       Full Julian Day.
#       nseconds        INTEGER       Number of secons since midnight.
#     OUTPUTS:
#       yyyymmddhhmmss  CHAR*         Full time as character string
#                                      Year length varies as appropriate.
#     Modifications:
#       D. Ovens (4/7/1999) Changed output of so year is full length
#                            no matter what the year is.
#**********************************************************************c
    if ($nseconds >= 86400 || $nseconds < 0) { ($julianday,$nseconds) = &jdaysec_increment($julianday,0,0,$nseconds); }
    ($month,$day,$year) = &caldat($julianday);
    $hour = int($nseconds / 3600);
    $minute = int(($nseconds - $hour*3600) / 60);
    $second = int($nseconds - $hour*3600 - $minute*60);
    $yyyymmddhhmmss = sprintf("%d%2.2d%2.2d%2.2d%2.2d%2.2d",
			      $year, $month, $day, $hour, $minute, $second);
    return $yyyymmddhhmmss;
} # end of function yyyymmddhhmmss_jdaysec

#------------------Perl Subroutine yyyyjjjhhmmss_jdaysec -----------------
sub yyyyjjjhhmmss_jdaysec {
    my ($julianday,$nseconds) = @_;
    my ($yyyyjjjhhmmss);
    my ($jjj, $julianday1, $month, $day, $year, $hour, $minute, $second);
#**********************************************************************c
#     yyyyjjjhhmmss_jdaysec returns the time as YYYYJJJHHMMSS (a 13+
#       character string) given an appropriate Julidan Day and number
#       of seconds since midnight
#
#     INPUTS:
#       julianday       INTEGER       Full Julian Day.
#       nseconds        INTEGER       Number of secons since midnight.
#     OUTPUTS:
#       yyyyjjjhhmmss   CHAR*         Full time as character string
#                                      Year length varies as appropriate.
#     Modifications:
#       D. Ovens (8/26/1999) Created from yyyymmddhhmmss_jdaysec.
#**********************************************************************c
    if ($nseconds >= 86400 || $nseconds < 0) { ($julianday,$nseconds) = &jdaysec_increment($julianday,0,0,$nseconds); }
    ($month,$day,$year) = &caldat($julianday);
    $julianday1 = &julday_jjjyyyy(1,$year);
    $jjj  = $julianday - $julianday1 + 1;
    $hour = int($nseconds / 3600);
    $minute = int(($nseconds - $hour*3600) / 60);
    $second = int($nseconds - $hour*3600 - $minute*60);
    $yyyyjjjhhmmss = sprintf("%d%3.3d%2.2d%2.2d%2.2d",
			      $year, $jjj, $hour, $minute, $second);
    return $yyyyjjjhhmmss;
} # end of function yyyyjjjhhmmss_jdaysec

#------------------Perl Subroutine jdaysec_increment ----------------------
sub jdaysec_increment {
    my($jday,$nsec,$incday,$incsec) = @_;
    my($jdaynew,$nsecnew);
#**********************************************************************c
#     jdaysec_increment returns the UTC/GMT Julian Day and number 
#       of seconds since midnight given an initial Julian Day, number 
#       of seconds since midnight, number of days to increment, and
#       number of seconds to incremnt.
#
#
#     INPUTS:
#       jday            INTEGER       Full julian day.
#       nsec            INTEGER       Number of seconds since midnight
#       incday          INTEGER       Number of days to increment.
#       incsec          INTEGER       Number of seconds to increment.
#     OUTPUTS:
#       jdaynew         INTEGER       Full julian day.
#       nsecnew         INTEGER       Number of seconds since midnight
#**********************************************************************c
    $jdaynew = $jday + $incday;
    $nsecnew = $nsec + $incsec;
    while ($nsecnew >= 86400) {
	$nsecnew = $nsecnew - 86400;
	$jdaynew = $jdaynew + 1;
    }
    while ($nsecnew < 0) {
	$nsecnew = $nsecnew + 86400;
	$jdaynew = $jdaynew - 1;
    }
    return ($jdaynew,$nsecnew);
} #  end of subroutine jdaysec_increment

#------------------Perl Subroutine julday_mmddyyyy ------------------------
sub julday_mmddyyyy {
#**********************************************************************c
#     This is Numerical Recipes, JULDAY.  It returns the full Julian
#       day given three integers of the month, day, and year.
#     INPUTS:
#       mm              INTEGER       Month.
#       id              INTEGER       Day of the month.
#       iyyy            INTEGER       Full year.
#     OUTPUT: 
#       Julian Day      INTEGER       Full julian day
#**********************************************************************c
    my($mm,$id,$iyyy) = @_;
    my($igreg,$ja,$jm,$jy,$julday_mmddyyyy);

    $igreg = 15+31*(10+12*1582);
    if ($iyyy == 0) {
	print "There is no Year Zero.\n";
	exit(1);
    }
    if ($iyyy < 0) { $iyyy++; }
    if ($mm > 2) {
        $jy = $iyyy;
        $jm = $mm + 1;
    } else {
        $jy = $iyyy - 1;
        $jm = $mm + 13;
    }
    $julday_mmddyyyy = int(365.25*$jy) + int(30.6001*$jm) + $id + 1720995;
    if ( ($id+31*($mm+12*$iyyy)) >= $igreg ) {
        $ja = int(0.01*$jy);
        $julday_mmddyyyy = $julday_mmddyyyy+2-$ja+int(0.25*$ja);
    }
    return $julday_mmddyyyy;
} # end of function julday_mmddyyyy

#------------------Perl Subroutine julday_jjjyyyy ------------------------
sub julday_jjjyyyy {
#**********************************************************************c
#     This is patterned after Numerical Recipes, JULDAY.  It returns the 
#       full Julian day given the day of the year and the year.
#     INPUTS:
#       jjj             INTEGER       Day of the year 1 to 366.
#       iyyy            INTEGER       Full year.
#     OUTPUT: 
#       Julian Day      INTEGER       Full julian day
#**********************************************************************c
    my($jjj,$iyyy) = @_;
    my($igreg,$ja,$jm,$jy,$julday_jjjyyyy);

    $igreg = 15+31*(10+12*1582);
    if ($iyyy == 0) {
	print "There is no Year Zero.\n";
	exit(1);
    }
    if ($iyyy < 0) { $iyyy++; }
    $jy = $iyyy - 1;
    $jm = 14;
    $julday_jjjyyyy = int(365.25*$jy) + int(30.6001*$jm) + $jjj + 1720995;
    if ( ($jjj+31*(13*$iyyy)) >= $igreg ) {
        $ja = int(0.01*$jy);
        $julday_jjjyyyy = $julday_jjjyyyy+2-$ja+int(0.25*$ja);
    }
    return $julday_jjjyyyy;
} # end of function julday_jjjyyyy

#------------------Perl Subroutine caldat ------------------------------
sub caldat {
#**********************************************************************c
#     This is Numerical Recipes CALDAT, the complement of julday_mmddyyyy.
#       Given a full Julian day, this returns the month, day, and year.
#   INPUT:
#       julian              INTEGER       Month.
#   OUTPUTS:
#       month           INTEGER       Month.
#       day             INTEGER       Day of the month.
#       year            INTEGER       Full year.
#**********************************************************************c
    my($julian) = @_;
    my($igreg,$ja,$jalpha,$jb,$jc,$jd,$je,$month,$day,$year);

    $igreg = 2299161;
    if ($julian >= $igreg) {
	$jalpha = int((($julian-1867216)-0.25)/36524.25);
	$ja     = $julian+1+$jalpha-int(0.25*$jalpha);
    } else {
        $ja     = $julian;
    }
    $jb = $ja+1524;
    $jc = int(6680.+(($jb-2439870)-122.1)/365.25);
    $jd = 365*$jc+int(0.25*$jc);
    $je = int(($jb-$jd)/30.6001);
    $day = $jb-$jd-int(30.6001*$je);
    $month = $je - 1;
    if ($month > 12) { $month = $month - 12; }
    $year = $jc - 4715;
    if ($month > 2) { $year = $year - 1; }
    if ($year <= 0) { $year = $year - 1; }
    return ($month,$day,$year);
} # end of subroutine caldat

#------------------Perl Subroutine i4time_yyyymmddhhmmss------------------
sub i4time_yyyymmddhhmmss {
#     INPUTS 
    my($year, $month, $day, $hour, $minute, $second) = @_;
#     OUTPUTS
    my ($i4time, $ier);
#**********************************************************************c
#     i4time_yyyymmddhhmmss returns the UTC/GMT i4time (number of seconds
#       since midnight Jan 1, 1970) given 6 integers containing year,
#       month, day, hour, minute, second.
#
#     NOTE: this may break at 3:14:08 UTC Jan 19 2038 when integer*4
#       cannot handle i4time = 2147483648
#           
#
#     INPUTS:
#       year            INTEGER       FULL YEAR ONLY
#       month           INTEGER       1 to 12
#       day             INTEGER       1 to 31
#       hour            INTEGER       0 to 23
#       minute          INTEGER       0 to 59
#       second          INTEGER       0 to 59
#     OUTPUTS:
#       i4time          INTEGER       Number of seconds since 1/1/1970.
#       ier             INTEGER       0 if successful, 1 if failure
#**********************************************************************c
    my($juldaybase,@ndays);

    @ndays = (0,31,29,31,30,31,30,31,31,30,31,30,31);
    $juldaybase = 2440588; # Jan 1, 1970
    $ier    = 0;

    if ($month < 1 || $month > 12 ||
	$day < 1 || $day > $ndays[$month] ||
	$hour < 0 || $hour > 23 ||
	$minute < 0 || $minute > 59 ||
	$second < 0 || $second > 59) {
# return error code.
#
	$ier = 1;
	print "error in i4time_yyyymmddhhmmss\n";
    }

    $i4time = (&julday_mmddyyyy($month,$day,$year) - $juldaybase)*86400 +
	($hour * 3600) + ($minute * 60) + $second;
    return $i4time;
}  # End of perl subroutine i4time_yyyymmddhhmmss

#------------------Perl Subroutine yyyymmddhhmmss_i4time ---------------
sub yyyymmddhhmmss_i4time {
#**********************************************************************c
#     yyyymmddhhmmss_i4time returns fulltime in yyyymmddhhmmss
#       plus year, month, day, hour, minute, seconds, status, and isDST
#       given i4time (# of seconds since 00:00 01-jan-70)
#
#     NOTE: this will break at 3:14:08 UTC Jan 19 2038 when integer*4
#       cannot handle i4time = 2147483648
#
#     INPUTS:
#       i4time          INTEGER       Number of seconds since 01-jan-1970
#       timezone        CHARACTER     Time zone.
#     OUTPUTS: 
#       yyyymmddhhmmss  CHAR*         Full time as character string.
#       year            INTEGER       Full year (to the extent that i4time
#                                      can give it, see NOTE above).
#       month           INTEGER       1 to 12
#       day             INTEGER       1 to 31
#       hour            INTEGER       0 to 23
#       minute          INTEGER       0 to 59
#       second          INTEGER       0 to 59
#       ier             INTEGER       0 if successful, 1 if failure
#       isdst           INTEGER       1 if Daylight Savings Time, 0 otherwise
#
#     Modifications:
#           D. Ovens (4/7/1999) Changed output of year to format %d.
#
#           D. Ovens (1/13/2000) Fixed it to work beyond the 32-bit changeover,
#                                1/19/2038 at 3:14:07 UTC.  Now, only obsolete
#                                routines use gmtime() and localtime().
#**********************************************************************c

    my($i4time,$timezone) = @_;
    my($julianday,$nseconds,$fulltime,$year,$month,$day,$hour,$min,$sec,$ier,$isdst) = "";
    local ($utc_local) = 8; # UTC is 8 hours later than Local Standard Time

    if (defined($i4time)) {
	$ier = 0;
    } else {
	$ier = 1;
	return ($fulltime,$year,$month,$day,$hour,$min,$sec,$ier,$isdst);
    }
    unless ($timezone) {
	$timezone = "UTC";
    }
    $timezone =~ tr/a-z/A-Z/;
    if ($timezone eq "EDT" || $timezone eq "EST") {
	$utc_local = 5;
    } elsif ($timezone eq "CDT" || $timezone eq "CST") {
	$utc_local = 6;
    } elsif ($timezone eq "MDT" || $timezone eq "MST") {
	$utc_local = 7;
    }
    ($julianday,$nseconds,$ier) = &jdaysec_i4time($i4time);
    if ($timezone ne "UTC") {
	($julianday,$nseconds,$timezone) = &timezone_shift($julianday,$nseconds,$utc_local,$timezone);
    }
    $fulltime = &yyyymmddhhmmss_jdaysec($julianday,$nseconds);
    $length = length($fulltime);
    $year    = substr($fulltime,0,($length-10));
    $month   = substr($fulltime,($length-10),2);
    $day     = substr($fulltime,($length-8),2);
    $hour    = substr($fulltime,($length-6),2); 
    $min     = substr($fulltime,($length-4),2);
    $sec     = substr($fulltime,($length-2),2);
    $isdst   = &dstcalc($month,$day,$nseconds,(($julianday+1)%7));
    return ($fulltime,$year,$month,$day,$hour,$min,$sec,$ier,$isdst);
}       # End of perl subroutine yyyymmddhhmmss_i4time

#------------------Perl Subroutine yearmonthdayhour12------------------
sub yearmonthdayhour12 {
#**********************************************************************c
#     yearmonthdayhour12 is a quick way to convert an i4time (number of
#       seconds since 01-jan-1970) into a (yy)yymmddhh for the most
#       most recent 00Z/12Z time.
#
#     INPUTS:
#       i4time          INTEGER       Number of seconds since 01-jan-1970
#       timezone        CHARACTER     "gmt" or "local"
#       yeardigits      CHARACTER     "2" or anything else (not 2 means full)
#       hour12          INTEGER       0 (use the time as given by $i4time) 
#                                     1 (use the 0Z or 12Z time preceding $i4time)    
#     OUTPUT:
#      $yearmonthdayhour12     yymmddhh or yyyymmddhh based yeardigits
#                               with year being full value if yyyymmddhh chosen
#                              -1 (failure)
#     Modifications:
#           D. Ovens (4/7/1999) Changed output of year to format %d.
#**********************************************************************c

    my ($i4time,$timezone,$yeardigits,$hour12) = @_;
    my ($yyyymmddhhmmss,$year,$mon,$day,$hr,$length,
	   $julianday,$nsec);

##   Use jdaysec_increment to add i4time seconds to 
##   Jan 1, 1970 (Julianday 2440588)
    ($julianday,$nsec) = &jdaysec_increment(2440588,0,0,$i4time);
    $yyyymmddhhmmss = &yyyymmddhhmmss_jdaysec($julianday,$nsec);

    $length = length($yyyymmddhhmmss);
    $year = substr($yyyymmddhhmmss,0,($length-10));
    $mon  = substr($yyyymmddhhmmss,($length-10),2);
    $day  = substr($yyyymmddhhmmss,($length-8),2);
    $hr   = substr($yyyymmddhhmmss,($length-6),2); 
    if ($hour12) { $hr = $hr - $hr % 12; }
    if ($yeardigits eq "2") {
	$yearmonthdayhour12  = sprintf("%2.2d%2.2d%2.2d%2.2d",substr($year,(length($year)-2),2),$mon,$day,$hr);
    } else { # return full year by default
	$yearmonthdayhour12  = sprintf("%d%2.2d%2.2d%2.2d",$year,$mon,$day,$hr);
    }
    return $yearmonthdayhour12;
}       # End of perl subroutine yearmonthdayhour12

#------------------Perl Subroutine jdaysec_i4time -----------------------
sub jdaysec_i4time {
    my ($i4time) = @_;
    my($julianday, $nseconds, $ier);
#**********************************************************************c
#     jdaysec_i4time returns the UTC/GMT Julian Day and number 
#       of seconds since midnight given i4time (# of seconds since 
#       00:00 01-jan-70)
#
#     INPUT:
#       i4time          INTEGER       Number of seconds since 01-jan-1970
#     OUTPUTS:
#       julianday       INTEGER       Full julian day.
#       nseconds        INTEGER       Number of seconds since midnight
#       ier             INTEGER       0 if successful, 1 if failure
#**********************************************************************c

##   Use jdaysec_increment to add i4time seconds to 
##   Jan 1, 1970 (Julianday 2440588)
    $ier = 0;
    ($julianday,$nseconds) = &jdaysec_increment(2440588,0,0,$i4time);
    return ($julianday, $nseconds, $ier);
} # end of jdaysec_i4time

#------------------Perl Subroutine i4time_jdaysec -----------------------
sub i4time_jdaysec {
    my ($julianday, $nseconds) = @_;
    my($i4time, $ier);
#**********************************************************************c
#     i4time_jdaysec returns the i4time (UTC/GMT # of seconds since 
#       00:00 01-jan-70) given the Julian Day and number 
#       of seconds since midnight.
#     NOTE: this routine will output a number bigger than 2^31, so
#           be careful with any dates prior or 01-jan-1970 and
#           after 18-jan-2038 to make sure you can handle the big number
#
#     INPUT:
#       julianday       INTEGER       Full julian day.
#       nseconds        INTEGER       Number of seconds since midnight
#     OUTPUTS:
#       i4time          INTEGER*8     Number of seconds since 01-jan-1970
#       ier             INTEGER       0 if successful, 1 if failure
#**********************************************************************c

##   Calculate seconds since Jan 1, 1970 (Julianday 2440588)
##   32-bit changeover is Jan 18, 2038 at 3:14:07 UTC
##   (Julianday 2465443 11647 sec)
    $i4time = ($julianday - 2440588)*86400 + $nseconds;
    return ($i4time);
} # end of i4time_jdaysec

#------------------Perl Subroutine dstcalc ------------------------------
sub dstcalc {
#**********************************************************************c
#     This is returns 1 if Daylight Savings Time is in effect and 0 if 
#       Standard time is in effect.
#     Based on first Sunday in April and last Sunday in October at 2 am.
#     INPUTS:
#       mm              INTEGER       Month.
#       dd              INTEGER       Day of the month.
#       ns              INTEGER       Seconds into the day.
#       dow             INTEGER       Day of week (0=Sunday, to 6=Saturday)
#     OPTIONAL INPUT:
#       timezone        INTEGER       hour difference UTC - local standard time
#                                      (DEFAULT is blank)
#                                     make calculations based on UTC time, 
#                                     which means shift at 10:00 UTC in April
#                                     and 9:00 UTC in October
#     OUTPUT: 
#                       INTEGER       1 = DST, 0 = not DST
#**********************************************************************c
    my($mm,$dd,$ns,$dow,$timezone) = @_;
    
    if ($mm < 4 || $mm > 10) {
	return 0;
    } elsif ($mm >= 5 && $mm <= 9) {
	return 1;
    } elsif ($mm == 4) {
	if ($dd > 7) {
	    return 1;
	} elsif ($dd >= ($dow+1)) {
	    if ($timezone) {
		if ($dow == 0 && $ns < (7200+$timezone*3600)) {
		    return 0;
		} else {
		    return 1;
		}
	    } else {
		if ($dow == 0 && $ns < 7200) {
		    return 0;
		} else {
		    return 1;
		}
	    }
	} else {
	    return 0;
	}
    } elsif ($mm == 10) {
	if ($dd < 25) {
	    return 1;
	} elsif ($dd < ($dow+25)) {
	    return 1;
	} elsif ($dow == 0) {
	    if ($timezone) { # UTC calculations
		if ($ns < (7200+($timezone-1)*3600)) {
		    return 1;
		} else {
		    return 0;
		}
	    } else { # local time calculations
		if ($ns < 7200) {
		    return 1;
		} else {
		    return 0;
		}
	    }
	} else {
	    return 0;
	}
    } # end of month checks
} # end of subroutine dstcalc

#------------------Perl Subroutine timezone_shift -------------------------
sub timezone_shift {
    my ($julianday,$nseconds,$utc_local,$timezone) = @_;
#**********************************************************************c
#     timezone_shift will shift the given time to/from local/UTC
#       based on the value of timezone input
#
#     INPUTS:
#       julianday       INTEGER      Julian Day
#       nseconds        INTEGER      seconds into Julian Day
#       utc_local       INTEGER      number of hours for (UTC - local std time)
#       timezone        CHARACTER    "local-UTC","UTC-local","local","UTC"
#     OUTPUTS:
#       julianday       INTEGER      Julian Day
#       nseconds        INTEGER      seconds into Julian Day
#       timezone        CHARACTER    "UTC", "PST", "PDT"
#**********************************************************************c
    my ($yyyymmddhhmmss,$length,$year,$yy,$mm,$dd,$hh,$nn,$ss);

    $yyyymmddhhmmss = &yyyymmddhhmmss_jdaysec($julianday,$nseconds);
    $length = length($yyyymmddhhmmss);
    $year = substr($yyyymmddhhmmss,0,($length-10));
    $yy   = substr($year,(length($year)-2),2);
    $mm   = substr($yyyymmddhhmmss,($length-10),2);
    $dd   = substr($yyyymmddhhmmss,($length-8),2);
    $hh   = substr($yyyymmddhhmmss,($length-6),2); 
    $nn   = substr($yyyymmddhhmmss,($length-4),2);
    $ss   = substr($yyyymmddhhmmss,($length-2),2);
    if ($timezone =~ /^(loc(al)?|LOC(AL)?)$/) {
	if ( &dstcalc($mm,$dd,$nseconds,(($julianday+1)%7)) ) {
	    $timezone = "PDT";
	} else {
	    $timezone = "PST";
	}
    } elsif ($timezone =~ /^(local|LOCAL)-(utc|UTC)$/) {
	$timezone = "UTC";
	if ( &dstcalc($mm,$dd,$nseconds,(($julianday+1)%7)) ) {
	    ($julianday,$nseconds) = &jdaysec_increment($julianday,$nseconds,0,($utc_local-1)*3600);
	} else {
	    ($julianday,$nseconds) = &jdaysec_increment($julianday,$nseconds,0,$utc_local*3600);
	}
    } elsif ($timezone =~ /^(UTC|utc)-(local|LOCAL)$/) {
	if ( &dstcalc($mm,$dd,$nseconds,(($julianday+1)%7),$utc_local) ) {
	    $timezone = "PDT";
	    ($julianday,$nseconds) = &jdaysec_increment($julianday,$nseconds,0,($utc_local-1)*-3600);
	} else {
	    $timezone = "PST";
	    ($julianday,$nseconds) = &jdaysec_increment($julianday,$nseconds,0,$utc_local*-3600);
	}
    } # end of known timezone choices
    return ($julianday,$nseconds,$timezone);
} # end of subroutine timezone_shift

## This code is used to make time_increment(time,i4,0,0,"unix") run about
##  100 times faster!
## Since quick_unix_time relies on localtime, it may break
##     at 3:14:08 UTC Jan 19 2038 when integer*4 cannot handle 
##     i4time = 2147483648
## 
sub quick_unix_time {
    my @days = ("Sun", "Mon", "Tue", "Wed", "Thu",
		"Fri", "Sat");
    my @mons = ("Jan", "Feb", "Mar", "Apr", "May", "Jun",
		"Jul", "Aug", "Sep", "Oct", "Nov", "Dec");
#
# NOTE: the following typo meant that I actually redefined $hour!!!
#    my $sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst,$year,$tzone;
# The parentheses are CRITICAL.    
    my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst,$year,$tzone);
    ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = 
	localtime($_[0]);
    $year += 1900;
    if ($ENV{TZ} && $ENV{TZ} ne "US/Pacific") {
	$tzone = $ENV{TZ};
	$tzone = "$tzone Daylight" if ($isdst);
    } else {
	$tzone = "PST";
	$tzone = "PDT" if ($isdst);
    }
    return sprintf "%s %s %d %2.2d:%2.2d:%2.2d %s %d",$days[$wday],$mons[$mon],$mday,$hour,$min,$sec,$tzone,$year;
} # end of subroutine quick_unix_time

########## THE FOLLOWING SUBROUTINES ARE OBSOLETE, BUT MUST BE ###########
########## KEPT FOR COMPATIBILITY WITH OLD CODE.   D. Ovens 11/10/1998 ###
#
;#- Perl Subroutine changetime (cp 8/29/97 from ~marka/nexrad/chmin.pl) ------
sub changetime_min {

;# input       $intime  = Original yymmddhhmm
;# return      $outtime = Changed yymmddhhmm after adding $deltmin

      my ($intime, $deltmin) = @_;
      my ($yr,$mn,$dy,$hr,$min,@NDAYS,$minch,$hrch,$DYCH,$MNCH,$YRCH);

      $yr  = substr( $intime, 0, 2);
      $mn  = substr( $intime, 2, 2);
      $dy  = substr( $intime, 4, 2);
      $hr  = substr( $intime, 6, 2);
      $min = substr( $intime, 8, 2);

      @NDAYS = (0,31,28,31,30,31,30,31,31,30,31,30,31);

      if( $yr%4 == 0 && ($yr%100 != 0 || $yr%1000 == 0) ) { $NDAYS[2] = 29; }
      else { $NDAYS[2] = 28; }

      $minch = $min + $deltmin;
      $hrch  = $hr;
      $DYCH  = $dy;
      $MNCH  = $mn;
      $YRCH  = $yr;

      while( $minch < 0 || $minch > 59 ) {
         if( $minch < 0 ) {
            $minch += 60;
            $hrch--;
            if( $hrch == -1 ) {
               $hrch += 24;
               $DYCH--;
               if ($DYCH == 0) {
                  $MNCH--;
                  if ($MNCH == 0) {
                     $MNCH = 12;
                     $YRCH--;
                     if($YRCH%4 == 0 && ($YRCH%100 != 0 || $YRCH%1000 == 0)) {
                        $NDAYS[2] = 29;
                     }
                  }
                  $DYCH = $NDAYS[$MNCH];
               }
            }
         }
         else {      #  $minch > 59
            $minch -= 60;
            $hrch++;
            if( $hrch == 24 ) {
               $hrch -= 24;
               $DYCH++;
               if ($DYCH > $NDAYS[$MNCH]) {
                  $MNCH++;
                  if ($MNCH == 13) {
                     $MNCH  = 1;
                     $YRCH++;
                     if ($YRCH%4 == 0) { $NDAYS[2] = 29; }
                  }
                  $DYCH = 1;
               }
            }
         }
      }
      if( length($MNCH)  == 1 ) { $MNCH  = "0" . $MNCH; }
      if( length($DYCH)  == 1 ) { $DYCH  = "0" . $DYCH; }
      if( length($hrch)  == 1 ) { $hrch  = "0" . $hrch; }
      if( length($minch) == 1 ) { $minch = "0" . $minch; }

      return ( "$YRCH$MNCH$DYCH$hrch$minch" );
}
;#--------- End of Perl Subroutine changetime----------------------------------

;#- Perl Subroutine expandtime_min (cp 8/29/97 from ~marka/nexrad/expmin.pl)---
sub expandtime_min {
########################################################################c
#input     $timeArg        =>  Abbreviated form of the requested time
#                               in form yymmddhh:mm
#input     $offsetCurTime  =>  Offset in seconds from current time, used in
#                              calulating the default $time when $timeArg
#                              is specified as a null string.
#input     $yeardigits     =>  DEFAULT is last 2.
#input     $fulloutput     =>  Output time in yyyymmddhhnnss format. DEFAULT no
#output    $time           =>  Fully expanded form of the requested time in
#                               the form yymmddhhmm.
# Modifications:
#                D. Ovens (6/23/1999) Added fulloutput option.
########################################################################c
 my( $timeArg, $offsetCurTime, $yeardigits, $fulloutput ) = @_;
 my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst
	,$curmin,$curhour,$curday,$curmonth,$curyear
	,@dayspermonth,$selyear,$selmonth,$selday,$selhour,$selmin
	,$time,$i);

 if ($timeArg ne "") { $offsetCurTime = 0; }

 ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = 
                                               gmtime(time-$offsetCurTime);
 $curmin   = $min;
 $curhour  = $hour;
 $curday   = $mday;
 $curmonth = ++$mon;
 $curyear  = $year + 1900;

 @dayspermonth = (31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
 if ($curyear % 4 == 0 && ($curyear % 100 != 0 || $curyear % 1000 == 0)) { $dayspermonth[1] = 29; }

 if( $timeArg =~ /^(\d*)[,.;:]?(\d{0,2})$/ ) {
    $timeArg = $1;
    $selmin  = $2;
    if( length($selmin) == 0 ) {
       if( length($1) == 0 ) {
          $selmin = $curmin;
       }
       else { $selmin = "00"; }
    }
    if( length($selmin) == 1 ) { $selmin = "0" . $selmin; }
 }

 if (length($timeArg) == 1) { $timeArg = "0" . $timeArg; }
 if ($timeArg eq "00") { $timeArg = $mday . $timeArg; }
 for ($i=length($timeArg); $i<10; $i++) {   # zero fill to ten digits
    $timeArg = "0" . $timeArg;
 }

 $selyear  = substr( $timeArg, -10, 4 );
 $selmonth = substr( $timeArg, -6, 2 );
 $selday   = substr( $timeArg, -4, 2 );
 $selhour  = substr( $timeArg, -2, 2 );
 if ($selyear eq "0000") { $selyear = $curyear; }
 elsif ($selyear =~ /^00(\d\d)/) { $selyear = substr($curyear,0,2) . "$1"; }
 if ($selmonth == "00") {
    $selmonth = $curmonth;
    if ($selday eq "00") {
       $selday = $curday;
       if ($selhour eq "00") {
          $selhour = $curhour;
       }
       if ($selhour > $curhour) {
          $selday--;
          if ($selday == 0) {
             $selmonth--;
             if ($selmonth == 0) {
                $selmonth = 12;
                $selyear--;
             }
             $selday = $dayspermonth[$selmonth-1];
          }
       }
    }
    elsif ($selday > $curday) {
       $selmonth--;
       if ( $selmonth == 0 ) {
          $selmonth = 12;
          $selyear--;
       }
    }
 }
   
 if (length($selhour ) == 1) { $selhour  = "0" . $selhour; }
 if (length($selday  ) == 1) { $selday   = "0" . $selday; }
 if (length($selmonth) == 1) { $selmonth = "0" . $selmonth; }

 if ($yeardigits > 2) {
     if ($fulloutput) {
	 $time = "$selyear$selmonth$selday$selhour${selmin}00";
     } else {
	 $time = "$selyear$selmonth$selday$selhour$selmin";
     }
 } else {
     if ($fulloutput) {
	 $time = substr($selyear,2,2) . "$selmonth$selday$selhour${selmin}00";
     } else {
	 $time = substr($selyear,2,2) . "$selmonth$selday$selhour$selmin";
     }
 }
 return( "$time" );

}    # End Perl subroutine expandtime_min
;#-------------------------------------------------------------------------

#---------- Perl Subroutine calctime --------------------------------------
sub calctime {

# input      $answer   = Time series request for time
#            $year     = Default GMT year 
#            $mon      = Default GMT month
#            $day      = Default GMT day of month
#            $hour     = Default GMT hour
#            $year4d   = return 4 digit year or 2 digit year [optional]
# return     $yymmddhh = derived time value

      my( $answer, $year, $mon, $day, $hour, $year4d ) = @_;
      my($yy,$mm,$dd,$hh,$length);
      ($yy, $mm, $dd, $hh) = split( ' ', $answer );
      unless ($year4d) {
	  if ($yy) { $yy = $yy % 100; }
	  if ($year) { $year = $year % 100; }
      }
      if( ($length = length($hh)) < 2 ) {
         if( $length == 0 ) {
             $hh = $hour;
             $length = length($hour);
         } 
         if( $length == 1 ) { $hh = "0" . $hh; }
      }
      if( ($length = length($dd)) < 2 ) {
         if( $length == 0 ) {
             $dd = $day;
             $length = length($day);
         } 
         if( $length == 1 ) { $dd = "0" . $dd; }
      }
      if( ($length = length($mm)) < 2 ) {
         if( $length == 0 ) {
             $mm = $mon;
             $length = length($mon);
         } 
         if( $length == 1 ) { $mm = "0" . $mm; }
      }
      if( ($length = length($yy)) < 2 ) {
         if( $length == 0 ) {
             $yy = $year;
             $length = length($year);
         } 
         if( $length == 1 ) { $yy = "0" . $yy; }
      }

      if ($year4d) {
	  $yy = 1900 + $yy;
	  return sprintf ("%4.4d%2.2d%2.2d%2.2d",$yy,$mm,$dd,$hh);
      } else {
	  return ( "$yy$mm$dd$hh" );
      }
}
#--------- End of Perl Subroutine calctime----------------------------------   

#---------- Perl Subroutine changetime10 ------------------------------------
sub changetime10 {
# inputs:       $timein  = YYYYMMDDHH
#               $changehour = number of hours to change $timein
# output:       $timeout = YYYYMMDDHH
    my($timein,$changehour) = @_;
    my($timeout);
    $timeout = &time_increment("${timein}0000",yy,0,($changehour*3600),"YYYYMMDDHH");
    return $timeout;
} # end of subroutine changetime10

#---------- Perl Subroutine changetime --------------------------------------
sub changetime {

# input       $intime  = Original yymmddhh
# return      $outtime = Changed yymmddhh after adding $delthr 

      my ($intime, $delthr) = @_;
      my ($yr,$mn,$dy,$ho,@NDAYS,$HRCH,$DYCH,$MNCH,$YRCH);

      $yr = substr( $intime, 0, 2);
      $mn = substr( $intime, 2, 2);
      $dy = substr( $intime, 4, 2);
      $ho = substr( $intime, 6, 2);

      @NDAYS = (0,31,28,31,30,31,30,31,31,30,31,30,31);

      if ($yr%4 == 0) { $NDAYS[2] = 29; }
      else { $NDAYS[2] = 28; }

      $HRCH = $ho + $delthr;
      $DYCH = $dy;
      $MNCH = $mn;
      $YRCH = $yr;

      while ($HRCH < 0 || $HRCH > 23) {
         if ($HRCH < 0) {
            $HRCH += 24;
            $DYCH--;
            if ($DYCH == 0) {
               $MNCH--;
               if ($MNCH == 0) {
                  $MNCH = 12;
                  $YRCH--;
                  if ($YRCH%4 == 0) { $NDAYS[2] = 29; }
               }
               $DYCH = $NDAYS[$MNCH];
            }
         }
         if ($HRCH > 23) {
            $HRCH -= 24;
            $DYCH++;
            if ($DYCH > $NDAYS[$MNCH]) {
               $MNCH++;
               if ($MNCH == 13) {
                  $MNCH  = 1;
                  $YRCH++;
                  if ($YRCH%4 == 0) { $NDAYS[2] = 29; }
               }
               $DYCH = 1;
            }
         }
      }
      if( length($MNCH) == 1 ) { $MNCH = "0" . $MNCH; }
      if( length($DYCH) == 1 ) { $DYCH = "0" . $DYCH; }
      if( length($HRCH) == 1 ) { $HRCH = "0" . $HRCH; }

      return ( "$YRCH$MNCH$DYCH$HRCH" );
}
#--------- End of Perl Subroutine changetime----------------------------------

#------------------Perl Subroutine expandtime------------------------------
sub expandtime {

#input     $timeArg        =>  Abbreviated form of the requested time
#input     $offsetCurTime  =>  Offset in seconds from current time, used in
#                              calulating the default $time when $timeArg
#                              is specified as a null string.
#output    $time           =>  Fully expanded form of the requested time in
#                               the form yymmddhh.

 my( $timeArg, $offsetCurTime ) = @_;
 my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst
	,$curhour,$curday,$curmonth,$curyear
	,@dayspermonth,$selyear,$selmonth,$selday,$selhour
	,$i,$time);


 if ($timeArg ne "") { $offsetCurTime = 0; }

 ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = 
                                               gmtime(time-$offsetCurTime);
 $curhour  = $hour;
 $curday   = $mday;
 $curmonth = ++$mon;
 $curyear  = $year;

 @dayspermonth = (31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
 if ((1900+$curyear) % 4 == 0) { $dayspermonth[1] = 29; }

 if (length($timeArg) == 1) { $timeArg = "0" . $timeArg; }
 if ($timeArg eq "00") { $timeArg = $mday . $timeArg; }
 for ($i=length($timeArg); $i<8; $i++) {   # zero fill to eight digits
    $timeArg = "0" . $timeArg;
 }
 $selyear  = substr( $timeArg, -8, 2 );
 $selmonth = substr( $timeArg, -6, 2 );
 $selday   = substr( $timeArg, -4, 2 );
 $selhour  = substr( $timeArg, -2, 2 );
 if ($selyear eq "00") { $selyear = $curyear; }
 if ($selmonth == "00") {
    $selmonth = $curmonth;
    if ($selday eq "00") {
       $selday = $curday;
       if ($selhour eq "00") {
          $selhour = $curhour;
       }
       if ($selhour > $curhour) {
          $selday--;
          if ($selday == 0) {
             $selmonth--;
             if ($selmonth == 0) {
                $selmonth = 12;
                $selyear--;
             }
             $selday = $dayspermonth[$selmonth-1];
          }
       }
    }
    elsif ($selday > $curday) {
       $selmonth--;
       if ( $selmonth == 0 ) {
          $selmonth = 12;
          $selyear--;
       }
    }
 }
   
 if (length($selhour ) == 1) { $selhour  = "0" . $selhour; }
 if (length($selday  ) == 1) { $selday   = "0" . $selday; }
 if (length($selmonth) == 1) { $selmonth = "0" . $selmonth; }

 $time = "$selyear$selmonth$selday$selhour";
 return( "$time" );

}    # End Perl subroutine expandtime
#-------------------------------------------------------------------------

1;

