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

I have a database that I need to massage the format of some dates. After sifting through numerous postings I believe I've finally figured out the bulk of the code I need.

The data looks like this:

26047|9/26/02|js|XBRV|893 Ronson Road||San Francisco|CA|96666|Matt|666 +-650-5114|matt@somewhere.com|710464|1|9/27/02|9/27/02|warranty|Yes| 26048|9/26/02|js|BEVT|13 West Kennedy Blvd.||Yourtown|FL|33456|Christi +an Carusso|713-867-1515||Tel-14|1|||non warranty ``cross ref: 26048|| 26049|9/26/02|js|Ultimate Products|1 South Sunset Drive||Tempe|AZ|8333 +1|Mike Goose|700-676-6006|goose@nowhere.com|RS-502,CC-95|1 each|||S/N + A145902||

What I need to do is change the format of the dates (if they exist) in fields 1, 14, & 15 from the current 9/26/02 format to 26-Sep-2002 format. Thanks to a posting by davorg I think I have a handle on how to do the conversions.

Where I am having a problem is testing if the date fields has data in it (I think):

Use of uninitialized value in numeric gt (>) at /usr/lib/perl5/5.6.1/T +ime/Local.pm line 91, <IN> line 1. Use of uninitialized value in numeric lt (<) at /usr/lib/perl5/5.6.1/T +ime/Local.pm line 91, <IN> line 1. Use of uninitialized value in numeric gt (>) at /usr/lib/perl5/5.6.1/T +ime/Local.pm line 92, <IN> line 1. Use of uninitialized value in numeric lt (<) at /usr/lib/perl5/5.6.1/T +ime/Local.pm line 92, <IN> line 1. Use of uninitialized value in join or string at /usr/lib/perl5/5.6.1/T +ime/Local.pm line 103, <IN> line 1. Use of uninitialized value in join or string at /usr/lib/perl5/5.6.1/T +ime/Local.pm line 103, <IN> line 1. Can't handle date (0, , , 7, 8, -1899) at ./convertdates.pl line 27

Any pointers are appreciated!

#!/usr/bin/perl -w use strict; use Time::Local; my $in_file="default.db"; my $out_file="properdates.db"; my ($sec, $min, $hr)=0; my @fmt_date=''; my @new=''; open (IN,"$in_file")||die "Sorry, but I can't open the file:$!"; open (OUT,">$out_file")||die "Sorry, but I can't append the file:$!"; while(<IN>){ chomp; my @line=split(/\|/); my @date=(split/\|/)[1,14,15]; foreach my $i (@date){ if ($i){ #my ($d, $m, $y)=split/\//, $date[$i]; my ($d, $m, $y)=split/\//, $i; $y-=1900; --$m; my $epoch=timelocal($sec, $min, $hr, $d, $m, $y); ($fmt_date[$i])=strftime('%d-%b-%Y', localtime($epoch)); } #end if } #end foreach push @new, qq($line[0]|$fmt_date[0]|$line[2]|$line[3]|$line[4]|$line +[5]|$line[6]|$line[7]|$line[8]|$line[9]|$line[10]|$line[11]|$line[12] +|$line[13]|$fmt_date[1]|$fmt_date[2]|$line[16]|$line[17]|$line[18]); push @new, "\n"; } #end while print OUT "@new"; close IN; close OUT;

Edited by footpad, ~ Sat Sep 28 02:01:00 2002 (UTC) : Placed <code> tags around error messages, per Consideration.

Replies are listed 'Best First'.
Re: Formatting dates
by sauoq (Abbot) on Sep 27, 2002 at 21:57 UTC

    I couldn't get that mess out of my mind. So I went back and wrote the whole thing as I might do it. It really is a simple task and probably doesn't require all of the mucking around with Time::Local and such.

    #!/usr/bin/perl -w use strict; my $in_file="default.db"; my $out_file="myproperdates.db"; open (IN,"$in_file") or die "Couldn't open $in_file: $!\n"; open (OUT,">$out_file") or die "Couldn't open $out_file: $!\n"; my $year = substr((localtime)[5], -2); # Purposeful. No y2k issue. See + below. my @month = qw( Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec ); while(<IN>){ # This is meant to deal with 2 digit dates. Its y2k issues aren't it +s own. s!(\d\d?)/(\d\d?)/(\d\d)!"$2-$month[$1-1]-".($3 > $year ? 19 : 20).$ +3!ge; print OUT; } close IN; close OUT;
    -sauoq
    "My two cents aren't worth a dime.";
    
Re: Formatting dates
by sauoq (Abbot) on Sep 27, 2002 at 20:57 UTC
    my $epoch=timelocal($sec, $min, $hr, $d, $m, $y);

    In the code you gave, you never set $sec, $min, or $hr. Those are uninitialized values and are probably causing your error.Update: Scratch that. You did set them. I must be blind. Update again: I take that back. You aren't setting them and that's the cause of your unitialized variables in Time::Local. The code, my ($sec,$min,$hr) = 0; is incorrect. You could use my ($sec,$min,$hr) = (0,0,0); but that is ugly. Just declare and set them separately.

    my $sec = 0; my $min = 0; my $hr = 0;
    $y-=1900;

    In this case, you don't want to subtract 1900 from your year because the data you are working with is two digit years. Subtracting 1900 from 02 is going to give you -1898. Oops. Because the date is already stored as two digits, you have a y2k problem. Depending on what your date ranges can be, you'll probably have to resort to making an intelligent guess which century that the date occured in. Add 0 or 100 as appropriate and then call timelocal.

    Update: Also. . .

    my ($d, $m, $y)=split/\//, $i;

    That's splitting in the wrong order. Your dates are M/D/Y not D/M/Y. It should be my ($m, $d, $y) = split m!/!, $i; instead.

    Update: And one more thing...

    ($fmt_date[$i])=strftime('%d-%b-%Y', localtime($epoch));

    The $fmt_date[$i] part of that line is wrong because $i should contain your original date as it appeared in @dates. You might fix that by putting my $c = 0; somewhere before your loop and changing the $i in that line to $c++. There would be better ways to do the whole thing but that's a quick fix.

    -sauoq
    "My two cents aren't worth a dime.";