Convert string to date?

C

Chet Douglas

I have a perl script that reads a text file and converts the format.
One line of the text file has a date that is extracted and read into
the output file. Here is the line with the date from the source text
file.

EFFECTIVE 12:00 AM ON 04/25/06, YOUR BUYING PRICES ARE CHANGED AS

Here is the section of the perl script that reads that line and sets
04/25/06 as $effDate

elsif (index($line, "EFFECTIVE") == 0) {
@words = split(/\s+/,$line);
$effDate = $words[4];
chop($effDate);
}

How can I get $effDate to be the next day in the output file? I need
to add 1 to 04/25/06 so the date will be 04/26/06 in the output file.
 
A

A. Sinan Unur

I have a perl script that reads a text file and converts the format.
One line of the text file has a date that is extracted and read into
the output file. Here is the line with the date from the source text
file.

EFFECTIVE 12:00 AM ON 04/25/06, YOUR BUYING PRICES ARE CHANGED AS

Here is the section of the perl script that reads that line and sets
04/25/06 as $effDate

elsif (index($line, "EFFECTIVE") == 0) {
@words = split(/\s+/,$line);
$effDate = $words[4];
chop($effDate);
}

How can I get $effDate to be the next day in the output file? I need
to add 1 to 04/25/06 so the date will be 04/26/06 in the output file.

You should use regular expressions when appropriate:

#!/usr/bin/perl

use strict;
use warnings;

use Time::Local;

my $s = q{EFFECTIVE 12:00 AM ON 04/25/06, YOUR BUYING PRICES ARE CHANGED
AS};

if ( $s =~ m{\A
EFFECTIVE
\s+
(\d\d):(\d\d)\s+(AM|PM)
\s+
ON
\s+
(\d\d)/(\d\d)/(\d\d)
}x ) {
my ($hr, $min, $ampm, $month, $day, $year) = ($1, $2, $3, $4, $5,
$6);
$hr %= 12;
$hr += 12 if $ampm eq 'PM';
my $time = timelocal(0, $min, $hr, $day, $month - 1, $year + 2000);
$time += (24 * 60 * 60); # fails with daytime savings
print scalar localtime $time;
}
__END__


Sinan
--
A. Sinan Unur <[email protected]>
(remove .invalid and reverse each component for email address)

comp.lang.perl.misc guidelines on the WWW:
http://augustmail.com/~tadmc/clpmisc/clpmisc_guidelines.html
 
I

it_says_BALLS_on_your forehead

Chet said:
I have a perl script that reads a text file and converts the format.
One line of the text file has a date that is extracted and read into
the output file. Here is the line with the date from the source text
file.

EFFECTIVE 12:00 AM ON 04/25/06, YOUR BUYING PRICES ARE CHANGED AS

Here is the section of the perl script that reads that line and sets
04/25/06 as $effDate

elsif (index($line, "EFFECTIVE") == 0) {
@words = split(/\s+/,$line);
$effDate = $words[4];
chop($effDate);
}

How can I get $effDate to be the next day in the output file? I need
to add 1 to 04/25/06 so the date will be 04/26/06 in the output file.

I would recommend Date::Calc::Add_Delta_YMD

http://search.cpan.org/~stbey/Date-Calc-5.4/Calc.pod
 
D

DJ Stunks

Chet said:
Here is the line with the date from the source text file.

EFFECTIVE 12:00 AM ON 04/25/06, YOUR BUYING PRICES ARE CHANGED AS

<snip>

How can I get $effDate to be the next day in the output file? I need
to add 1 to 04/25/06 so the date will be 04/26/06 in the output file.

Well, Chet,

If you don't mind the fact that Date::Manip is as slow as molasses, and
you like the fact that it can do almost anything you want, why don't
you try the following out for size:

#!/usr/bin/perl

use strict;
use warnings;

use Date::Manip;

$_ = q{EFFECTIVE 12:00 AM ON 04/25/06, YOUR BUYING PRICES...};
my $delta = '+1 days';

my $effDate;

if ( my ($time,$date) = m{ ([:\d]+ [ ] [AP]M) .+? ([/\d+]+) }x ){
$effDate = UnixDate( DateCalc("$date $time",$delta), '%D');
}

print "effDate: $effDate\n";

__END__

HTH,
-jp
 
T

Tad McClellan

Chet Douglas said:
How can I get $effDate to be the next day in the output file? I need
to add 1 to 04/25/06 so the date will be 04/26/06 in the output file.


use Date::Calc qw/Add_Delta_Days/;

....

sub add_one_day {
my($today) = @_; # MM/DD/YY

my($m, $d, $y) = split m#/#, $today;

my($year, $mon, $day) = Add_Delta_Days( $y+2000, $m, $d, 1 );

return sprintf '%02d/%02d/%02d', $mon, $day, $year-2000;
}
 
C

Chet Douglas

A. Sinan Unur said:
You should use regular expressions when appropriate:

#!/usr/bin/perl

use strict;
use warnings;

use Time::Local;

my $s = q{EFFECTIVE 12:00 AM ON 04/25/06, YOUR BUYING PRICES ARE CHANGED
AS};

if ( $s =~ m{\A
EFFECTIVE
\s+
(\d\d):(\d\d)\s+(AM|PM)
\s+
ON
\s+
(\d\d)/(\d\d)/(\d\d)
}x ) {
my ($hr, $min, $ampm, $month, $day, $year) = ($1, $2, $3, $4, $5,
$6);
$hr %= 12;
$hr += 12 if $ampm eq 'PM';
my $time = timelocal(0, $min, $hr, $day, $month - 1, $year + 2000);
$time += (24 * 60 * 60); # fails with daytime savings
print scalar localtime $time;
}

Sinan,

The code you wrote works, but the date is outputed as "Wed Apr 26
00:00:00 2006" I want it to be "04/26/06" with no time. What do I need
to modify to get that format?
 
P

Paul Lalli

The code you wrote works, but the date is outputed as "Wed Apr 26
00:00:00 2006" I want it to be "04/26/06" with no time. What do I need
to modify to get that format?

You need POSIX's stftime function:

perldoc POSIX
man strftime

Read both of those, and let us know if you can't get it the way you
want it after that.

Paul Lalli
 
C

Chet Douglas

I think I've come up with a simple solution. The file I'm converting
is read to STDIN

$cat filename | perlscript.pl

'filename' contains this line
EFFECTIVE 12:00 AM ON 04/25/06, YOUR BUYING PRICES ARE CHANGED AS

Here is what I put in the perl script

#!/usr/bin/perl

elsif (index($line, "EFFECTIVE") == 0) {
@words = split(/\s+/,$line);
$date = $words[4];

if ( $date =~ m{(\d\d)/(\d\d)/(\d\d)} ) {
my ($month, $day, $year) = ($1, $2, $3);
$effDate = sprintf("%02d/%02d/%02d", $month, $day + 1,
$year);
}

}



This seems to work and formats $effDate as 04/26/06. Thanks to
everyone for your help!
 
D

DJ Stunks

Chet said:
I think I've come up with a simple solution. The file I'm converting
is read to STDIN

$cat filename | perlscript.pl

'filename' contains this line
EFFECTIVE 12:00 AM ON 04/25/06, YOUR BUYING PRICES ARE CHANGED AS

Here is what I put in the perl script

#!/usr/bin/perl

elsif (index($line, "EFFECTIVE") == 0) {
@words = split(/\s+/,$line);
$date = $words[4];

if ( $date =~ m{(\d\d)/(\d\d)/(\d\d)} ) {
my ($month, $day, $year) = ($1, $2, $3);
$effDate = sprintf("%02d/%02d/%02d", $month, $day + 1,
$year);
}

}



This seems to work and formats $effDate as 04/26/06. Thanks to
everyone for your help!

Yep, that's simple alright. However, I think in 2 days you might begin
to notice a problem...

Why did you ask if you did not intend to take anyone's advice?

-jp
 
C

Chet Douglas

DJ said:
Chet said:
I think I've come up with a simple solution. The file I'm converting
is read to STDIN

$cat filename | perlscript.pl

'filename' contains this line
EFFECTIVE 12:00 AM ON 04/25/06, YOUR BUYING PRICES ARE CHANGED AS

Here is what I put in the perl script

#!/usr/bin/perl

elsif (index($line, "EFFECTIVE") == 0) {
@words = split(/\s+/,$line);
$date = $words[4];

if ( $date =~ m{(\d\d)/(\d\d)/(\d\d)} ) {
my ($month, $day, $year) = ($1, $2, $3);
$effDate = sprintf("%02d/%02d/%02d", $month, $day + 1,
$year);
}

}



This seems to work and formats $effDate as 04/26/06. Thanks to
everyone for your help!

Yep, that's simple alright. However, I think in 2 days you might begin
to notice a problem...

Why did you ask if you did not intend to take anyone's advice?

-jp

I did take the advice, I'm not a programmer, no surprise I'm sure, and
could not have done this without the groups help. How does this look.

#!/usr/bin/perl

use Time::Local;
use POSIX 'strftime';

--CUT--
elsif (index($line, "EFFECTIVE") == 0) {
@words = split(/\s+/,$line);
$effDate = $words[4];
chop($effDate);
if ($effDate =~ m{(\d\d)/(\d\d)/(\d\d)}) {
my ($month, $day, $year) = ($1, $2, $3);
my $time = timelocal(0, 0, 0, $day, $month - 1, $year +
2000);
$time += (24 * 60 * 60); # adds one day
$effDate = strftime("%m/%d/%y", localtime $time);
}
}
--End Cut--
 
J

John W. Krahn

Chet said:
I did take the advice, I'm not a programmer, no surprise I'm sure, and
could not have done this without the groups help. How does this look.

So so.
#!/usr/bin/perl

use warnings;
use strict;
use Time::Local;
use POSIX 'strftime';

--CUT--
elsif (index($line, "EFFECTIVE") == 0) {
@words = split(/\s+/,$line);
$effDate = $words[4];
chop($effDate);

chop() removes the last character from the string $effDate *no matter what it
is*. You may have thought that chop() was removing a newline but there is no
newline because split( /\s+/ ) already removed it.
if ($effDate =~ m{(\d\d)/(\d\d)/(\d\d)}) {

If the original $effDate contained eight characters like you show in the
pattern above then after chop() it would only contain seven characters and the
pattern would not match.
my ($month, $day, $year) = ($1, $2, $3);
my $time = timelocal(0, 0, 0, $day, $month - 1, $year +
2000);
$time += (24 * 60 * 60); # adds one day
$effDate = strftime("%m/%d/%y", localtime $time);
}
}
--End Cut--


John
 
D

Dr.Ruud

Chet Douglas schreef:
#!/usr/bin/perl

use Time::Local;
use POSIX 'strftime';

Alternative:

use POSIX qw( strftime ) ;

--CUT--
elsif (index($line, "EFFECTIVE") == 0) {

I would use single quotes, 'EFFECTIVE' or q{EFFECTIVE}.

Variant:
elsif ( $line =~ /^EFFECTIVE/ ) {

which I think is easier to read (and might be a tad slower but that does
not matter here).

@words = split(/\s+/,$line);

I would use ' ' instead of /\s+/ (see perldoc -f split) even already is
made sure that $line doesn't start with a whitespace.
Further, you can put a limit on split.

@words = split '', $line, 6; # date is 5th, rest is 6th
$effDate = $words[4];
chop($effDate);


if ($effDate =~ m{(\d\d)/(\d\d)/(\d\d)}) {

OK, stop. You should really do it more like Sinan showed in his first
reply.

my ($month, $day, $year) = ($1, $2, $3);
my $time = timelocal(0, 0, 0, $day, $month - 1, $year
+ 2000);
$time += (24 * 60 * 60); # adds one day
$effDate = strftime("%m/%d/%y", localtime $time);
}
}
--End Cut--


#!/usr/bin/perl
use strict;
use warnings;

use POSIX qw( mktime );

my $s = q{EFFECTIVE 05:30 PM ON 04/30/06, YOUR BUYING PRICES ARE CHANGED
AS};

if ( $s =~ m{\A
EFFECTIVE\s+
[0-2][0-9]:[0-5][0-9]\s+ # 05:30
[AP]M\s+ # PM
ON\s+ # ON
([01][0-9])/([0-3][0-9])/([0-9][0-9]), # 04/30/06,
}x ) {


my $time = mktime( 0, 0, 12 # noon [1]
, $2 + 1 # add 1 day
, $1 - 1 # 0 = January
, $3 + 100 # 0 = 1900
) ;

my ( $d, $m, $y ) = (localtime($time))[3..5] ;

printf '%02d/%02d/%04d', $m + 1, $d, $y + 1900 ;
}


[1] See `perldoc -q yesterday` about DST.
 
J

John W. Krahn

Dr.Ruud said:
Chet Douglas schreef:

I would use ' ' instead of /\s+/ (see perldoc -f split) even already is
^^^ ^^^^^
made sure that $line doesn't start with a whitespace.
Further, you can put a limit on split.

@words = split '', $line, 6; # date is 5th, rest is 6th
^^
split( '' ) is the same as split( // ) which splits $line into individual
characters.


John
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,774
Messages
2,569,598
Members
45,150
Latest member
MakersCBDReviews
Top