TyneBridges
TyneBridges

Reputation: 57

My function to convert dates leaves out the month

I have a function and the string fed into it is a date in US format from Sybase. I'm simply trying to put it into numeric format so I can do a date comparison. For example, if I sent Sep 12 2019 string as an argument, I would expect the output to be 9-12-2019. However, $mon appears to be always empty. I tried using chomp on $ms in case it somehow had a CR on the end, but that made no difference.

sub rnumeric
{  my ($d) = @_; # The parameter fed to this function
   print "Date to convert is $d ";
   my $ms = substr $d, 0, 3;
   if ($ms eq "Jan") { my $mon = "1" };
   if ($ms eq "Feb") { my $mon = "2" };
   if ($ms eq "Mar") { my $mon = "3" };
   if ($ms eq "Apr") { my $mon = "4" };
   if ($ms eq "May") { my $mon = "5" };
   if ($ms eq "Jun") { my $mon = "6" };
   if ($ms eq "Jul") { my $mon = "7" };
   if ($ms eq "Aug") { my $mon = "8" };
   if ($ms eq "Sep") { my $mon = "9" };
   if ($ms eq "Oct") { my $mon = "10"};
   if ($ms eq "Nov") { my $mon = "11"};
   if ($ms eq "Dec") { my $mon = "12"};
   my $day = trim(substr $d, 4, 2);
   my $yr = substr $d, 7, 4;
   my $d = $mon."-".$day."-".$yr;
   return $d;
}

Edit - sample output from "Print" statements.

Item overdue Date to convert is Jan  9 2015 11:59:00:000PM Our due date is -9-2015

Item overdue Date to convert is Feb  6 2014 11:59:00:000PM Our due date is -6-2014

Item overdue Date to convert is Feb  6 2014 11:59:00:000PM Our due date is -6-2014

Item overdue Date to convert is Jan 12 2015 11:59:00:000PM Our due date is -12-2015

Item overdue Date to convert is Jan 12 2015 11:59:00:000PM Our due date is -12-2015

Item overdue Date to convert is Sep  8 2016 11:59:00:000PM Our due date is -8-2016

Item overdue Date to convert is Sep  8 2016 11:59:00:000PM Our due date is -8-2016

Item overdue Date to convert is Oct  4 2013 11:59:00:000PM Our due date is -4-2013

I got the trim function from a helpful post online-I've used it for a while and it does work, although the regular expression logic it uses is beyond me.

sub trim
{ my $s = shift; $s =~ s/^\s+|\s+$//g; return $s };

Unfortunately I can't use use strict because I have to open the Sybase database with code provided by the host, who didn't use it, meaning that it throws up problems with their code that I can't fix.

Upvotes: 1

Views: 73

Answers (2)

brian d foy
brian d foy

Reputation: 132832

If you store the name to number mapping in a hash, you can simply lookup the number. Most of your code then disappears:

use v5.10;

print rnumeric( 'Sep 12 2019' );
sub rnumeric {
    state %Months = map { state $n = 1; $_ => $n++ } qw(
        Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec );
    my( $month_name, $day, $year ) = split /\s+/, $_[0];
    join '-', $Months{$month_name}, $day, $year;
    }

If you don't like that map, you can assign the numbers yourself:

use v5.10;

print rnumeric( 'Sep 12 2019' );
sub rnumeric {
    state %Months = qw(
        Jan 1 Feb 2 Mar 3 Apr 4  May 5  Jun 6
        Jul 7 Aug 8 Sep 9 Oct 10 Nov 11 Dec 12);
    my( $month_name, $day, $year ) = split /\s+/, $_[0];
    join '-', $Months{$month_name}, $day, $year;
    }

But, I'd rather let something else think about this. The Time::Piece module from the Standard Library can do it. Give it a format to recognize and parse the date, then another format to put it back together:

use v5.10;
use Time::Piece;

print rnumeric( 'Sep 12 2019' );
sub rnumeric {
    Time::Piece
        ->strptime( $_[0], "%b %d %Y" )
        ->strftime( '%-m-%-d-%Y' )
    }

The format like %-m uses the hyphen to strip leading zeros. If you want the leading zeros, it would be just %m.

Upvotes: 3

toolic
toolic

Reputation: 62096

You need to use strict and warnings. These will show you where your mistakes are. You need to scope your variables properly. It is good that you declare variables with my, but you should only declare each variable once.

use warnings;
use strict;

print rnumeric('Sep 12 2019');
print "\n";

sub rnumeric
{  my ($d) = @_; # The parameter fed to this function
   print "Date to convert is $d ";
   my $ms = substr $d, 0, 3;
   my $mon;
   if ($ms eq "Jan") { $mon = "1" };
   if ($ms eq "Feb") { $mon = "2" };
   if ($ms eq "Mar") { $mon = "3" };
   if ($ms eq "Apr") { $mon = "4" };
   if ($ms eq "May") { $mon = "5" };
   if ($ms eq "Jun") { $mon = "6" };
   if ($ms eq "Jul") { $mon = "7" };
   if ($ms eq "Aug") { $mon = "8" };
   if ($ms eq "Sep") { $mon = "9" };
   if ($ms eq "Oct") { $mon = "10"};
   if ($ms eq "Nov") { $mon = "11"};
   if ($ms eq "Dec") { $mon = "12"};
   my $day = trim(substr $d, 4, 2);
   my $yr = substr $d, 7, 4;
   $d = $mon."-".$day."-".$yr;
   return $d;
}

Upvotes: 2

Related Questions