http://www.perlmonks.org?node_id=320383

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

Take a look at this script;
#!perl use strict;use warnings; use Time::localtime; print "substr month= " . (substr("0" . localtime->mon() + 1, -2)) . "\ +n"; print "substr day= " . (substr("0" . localtime->mday(), -2)) . "\n"; print "sprintf month= " . (sprintf "%02d", localtime->mon() + 1) . "\n +"; print "sprintf day= " . (sprintf "%02d", localtime->mday()) . "\n";
It returns the following;
>perl pad.pl substr month= 1 substr day= 09 sprintf month= 01 sprintf day= 09
Now, I know the first two lines are not a good way to pad. I found some nodes on Perlmonks that showed a better way, which is the last two lines. The problem is I'm perplexed as to the first result. Why does substr month only return a 1 instead of 01?
I'm using ActiveState Perl 5.8.0 running under Win32. Thanks.

Replies are listed 'Best First'.
Re: padding/substr quirk
by Corion (Patriarch) on Jan 10, 2004 at 21:38 UTC

    Operator precedence:
    Your expression gets parsed as

    ("0" . localtime->mon()) + 1

    which evaluates to "1". Putting parentheses around the expressions helps :

    '0' . (localtime->mon +1)
    perl -MHTTP::Daemon -MHTTP::Response -MLWP::Simple -e ' ; # The $d = new HTTP::Daemon and fork and getprint $d->url and exit;#spider ($c = $d->accept())->get_request(); $c->send_response( new #in the HTTP::Response(200,$_,$_,qq(Just another Perl hacker\n))); ' # web
Re: padding/substr quirk
by Zed_Lopez (Chaplain) on Jan 10, 2004 at 21:51 UTC

    It doesn't have to do with substr -- it's operator precedence: . and + have equal precedence and left associativity. So "0" . localtime->mon() + 1 is the same as ("0" . localtime->mon()) + 1 -- it performs the concatenation operation first, resulting in "00", which is converted to a number, 0, for the addition, resulting in 1 (for the current month, January).

    bash-2.05b$ perl -MTime::localtime -e 'print "0" . localtime->mon() + + 1, "\n"' 1 bash-2.05b$ perl -MTime::localtime -e 'print +("0" . localtime->mon()) + + 1, "\n"' 1 bash-2.05b$ perl -MTime::localtime -e 'print "0" . (localtime->mon() + + 1), "\n"' 01
Re: padding/substr quirk
by pg (Canon) on Jan 11, 2004 at 00:19 UTC

    You already got your immediate answer from Corion and Zed_lopez.

    Next time, if a similar problem rises, or you need to find out the precedence or associativity of operators, where can you find the answer?

    perlop

    With the help of perlop, next time it is your turn to help others ;-)

      Or feed it to B::Deparse:
      $ perl -MO=Deparse,-p #!perl use strict;use warnings; use Time::localtime; print "substr month= " . (substr("0" . localtime->mon() + 1, -2)) . "\ +n"; print "substr day= " . (substr("0" . localtime->mday(), -2)) . "\n"; print "sprintf month= " . (sprintf "%02d", localtime->mon() + 1) . "\n +"; print "sprintf day= " . (sprintf "%02d", localtime->mday()) . "\n"; ^D
      which gives:
      use Time::localtime; BEGIN {${^WARNING_BITS} = "UUUUUUUUUUUU"} use strict 'refs'; print((('substr month= ' . substr((('0' . localtime()->mon) + 1), (-2) +)) . "\n") ); print((('substr day= ' . substr(('0' . localtime()->mday), (-2))) . "\ +n")); print((('sprintf month= ' . sprintf('%02d', (localtime()->mon + 1))) . + "\n")); print((('sprintf day= ' . sprintf('%02d', localtime()->mday)) . "\n")) +;