Beefy Boxes and Bandwidth Generously Provided by pair Networks
Clear questions and runnable code
get the best and fastest answer
 
PerlMonks  

Expanding dates

by jgordin (Initiate)
on Feb 13, 2001 at 00:07 UTC ( [id://57967]=perlquestion: print w/replies, xml ) Need Help??

jgordin has asked for the wisdom of the Perl Monks concerning the following question:

I have a program that is supposed to take a bunch of log files that are named by their dates (ie, February 12, 2001 is 20010212) and grab pieces of data from them. However, I need to make it so a user can get a range of dates. For example the user should be able to enter 2000 200102 to get all the records for 2000 through 200102. I really need it to expand to 2000* and 200101* 200102* all on one line. Any one have thoughts on how to do this? Thanks

Replies are listed 'Best First'.
Re: Expanding dates
by Corion (Patriarch) on Feb 13, 2001 at 00:22 UTC

    Update:Test your code before you press that pesky Submit button ...

    You want to do some globbing on the filenames. This could be done with the perlfunc:glob() builtin, but you also want some ordering.

    Here is one approach :

    • If a start date is given too short, append 01 to it until it is long enough. This will expand 2000 to 20000101, but it will expand 19 to 19010101, which might not be what you want.
      my ($startdate, $enddate); $startdate .= "01" while( length( $startdate ) <= 8 ); $enddate .= "01" while( length( $enddate ) <= 8 );
    • Then, as you have fully specified dates, remark that date $a is later in time than date $b when the string comparision $a gt $b is true. We will use this to step through the list of all logfiles and spew out those that are in the right timeslot :
      my (@logfilelist); @logfilelist = sort @logfilelist; # Cut away everything that is too early while ($#logfilelist > -1 && $startdate lt @logfilelist[0]) { shift @logfilelist; }; # Cut away everything that is too late while ($#logfilelist > -1 && $enddate gt @logfilelist[-1]) { pop @logfilelist; }; # Now, @logfilelist contains all the logfiles in question
    Take a look at File::Find to see how you can get a list of all files in a directory, other interesting reading is the readdir() function.

Re: Expanding dates
by Masem (Monsignor) on Feb 13, 2001 at 00:27 UTC
    OTTOMH, assuming that your input is "X Y" where that is the range..
    <INPUT>; /^(\d*)\s*(\d*)/; #split input ($first, $second) = ($1, $2); $first =~ /(\d{4})(\d{2})?(\d{2})?/; # split the year, mo, and day $fyear = $1; $fmon = defined( $2 ) ? $2 : 1; #if not specified, use 1 $fday = defined( $3 ) ? $3 : 1; #ditto $second =~ /(\d{4})(\d{2})?(\d{2})?/; # split the year, mo, and day $syear = $1; $smon = defined( $2 ) ? $2 : 1; #if not specified, use 1 $sday = defined( $3 ) ? $3 : 1; #ditto # got input, now to 'expand' my @list; for ( my $y = $fyear; $y <= $syear; $y++ ) { for ( my $m = ( $y==$fyear ) ? $fmon; 1 ; $m <= ( $y==$syear) ? $smon : 12; $m++ ) { for( my $d = ( ( $y==$fyear) && ($m==$fmon) ) ? $fday : 1 ; $d <= ( ( $y==$syear) && ($m==$smon) ) ? $sday : 31 ; $d++) { push @list, sprintf("%04d%02d%02d", $y, $m, $d); } } } # And now @list holds an expanded list between the first # date and second, including 'fake' days that probably can # be ignored... maybe include here a test to remove the # bogus entires: my @goodlist; foreach $i @list { if ( -x $i ) { push @goodlist, $i; } } # note that @list or @goodlist will be already sorted in # date order...

    Edit: 2001-03-03 by neshura

      While it looks like this will work, it will take a lot longer than Corion's. Also, you should use < code> tags instead of < pre> tags
      It would be faster to do a readdir and weed out the files outside the range. Doing a file test for every possibilty can be a bit disk intensive. Crossing the century boundry isn't much of a problem since the file range format is done so that the file for Dec 20, 1999 is less than Jan 4, 2001. You method does make sure that non-dates are not listed.
      I was wondering if this question could be a homework question, which stops me from doing a full solution. (well, that and I should be working...)
Re: Expanding dates
by seeker (Curate) on Feb 13, 2001 at 01:39 UTC
    I had to something similar to examine log files that were in the same format (yyyymmdd). The user was allowed to specify a range including hours, minutes and seconds for the contents of the file. I won't go into any more detail for the same reson about homework that others have mentioned. However, a good way to check dates is to use epoch time. See also Time::Local.

    Good luck

Re: Expanding dates
by Anonymous Monk on Feb 13, 2001 at 05:18 UTC
    Overkill, but........in the event that this is homework ;-), I'll let you figure out what's going on.
    $HelpMessage = " <date/range/week> = YYYYMMDD = individual day YYYYMMDD.YYYYMMDD = series of individual days YYYYMMDD-YYYYMMDD = weeklong reporting period -YYYYMMDD = weeklong reporting period "; ################################################################ if (index($PERIODIN,"-") == 0) { $periodlength = "day"; } else { $periodlength = "week"; } if (!defined $InFileDir) { if ($R_OR_I ne "a" && $R_OR_I ne "b") { if (!(defined $Special)) { $rori = $R_OR_I; } else { $rori = $R_OR_I . "s"; } } elsif ($R_OR_I eq "a") { if (defined $AggrExceptions) { $rori = "ae"; } elsif (defined $Config || defined $Report) { $rori = "ap"; } else { $rori = "ar"; } } elsif ($R_OR_I eq "b") { $rori = "b"; } $InFileDir = $InFileDirX{$rori,$periodlength}; } if (!(-d $InFileDir)) {die "\n Directory $InFileDir \n does not exist\n\n";} $MonthDay[1] = $MonthDays[3] = $MonthDays[5] = $MonthDays[7]=31; $MonthDays[8] = $MonthDays[10] = $MonthDays[12] = 31; $MonthDays[4] = $MonthDays[6] = $MonthDays[9] = $MonthDays[11]=30; $MonthDays[2] = 28; $Leap{1996} = $FakeEndFeb{19960228} = 1; $Leap{2000} = $FakeEndFeb{20000228} = 1; $Leap{2004} = $FakeEndFeb{20040228} = 1; $Leap{2008} = $FakeEndFeb{20080228} = 1; $Leap{2012} = $FakeEndFeb{20120228} = 1; if (index($PERIODIN,".") == 0) { $numdates = 1; if (substr($PERIODIN,1,1) eq "-") { $begdate = $enddate = substr($PERIODIN,2); for (1..6) { $begdate = &getprevday($begdate); } $date[1] = $begdate . "-" . $enddate; } else { $date[1] = $PERIODIN; } } else { ($begdate, $enddate, @junkjunk) = split(/\./,$PERIODIN); $numdates = 1; $date[1] = $perd = $begdate; while ($perd < $enddate) { $numdates++; $date[$numdates] = $perd = &getnextday($perd); } } sub getnextday { local($today) = @_; local($nextday); $nyr = int($today / 10000); $nmo = int(($today - (10000 * $nyr)) / 100); $nda = $today - (10000 * $nyr) - (100 * $nmo) + 1; if (($nmo != 2 && $nda > $MonthDays[$nmo]) || ($nmo == 2 && (!(defined $Leap{$nyr})) && $nda > 28) || ($nmo == 2 && (defined $Leap{$nyr}) && $nda > 29)) { $nda = 1; $nmo = $nmo + 1; if ($nmo > 12) { $nmo = 1; $nyr = $nyr + 1 } } $nextday = $nyr * 10000 + $nmo * 100 + $nda; } sub getprevday { local($today) = @_; local($prevday); $pyr = int($today / 10000); $pmo = int(($today - (10000 * $pyr)) / 100); $pda = $today - (10000 * $pyr) - (100 * $pmo) - 1; if ($pda == 0) { $pmo = $pmo - 1; if ($pmo == 0) { $pyr = $pyr - 1; $pmo = 12; } if ($pmo != 2) {$pda = $MonthDays[$pmo];} elsif (defined $Leap{$pyr}) {$pda = 29;} else {$pda = 28;} } $prevday = $pyr * 10000 + $pmo * 100 + $pda; }

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://57967]
Approved by root
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others rifling through the Monastery: (3)
As of 2024-04-13 02:29 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found