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

Hi Monks,

This is a bit of code I don't fully understand:
sub format_time{ my ( $h, $m, $s ) = @_; ... if ( length( $h ) < 2 ) { $h = "0" . $h; } if ( length( $m ) < 2 ) { $m = "0" . $m; } return $h . $m . $s2; } print format_time( 9, 5, 13 )."\n"; print format_time( 12, 34, 50 )."\n"; __OUTPUT__ 905 1235
I basically round the times and want to add a 0 in front of the minutes and hours if they have less than 2 chars anyway. This works fine for minutes but for some reason the 0 are "magically" replaced with a space character whenever used for an hour. I do not get the reason for this.

I am using AS Perl 5.8.4 Build 810.

Cheers for any help.

Replies are listed 'Best First'.
Re: scalar number with preceding 0.
by davido (Cardinal) on Jul 26, 2004 at 15:26 UTC
    You should be using sprintf or printf if you want to ensure that numbers come out with the leading zeros. That's more reliable, and easier to do.

    Dave

      I know, yet I would like what causes this strange effect. I have atually some more lines in my code and have differnt return formats, so I just want to know, why this is replacing the leading 0 with a space.
      It is a bit strange to me, as the minutes are always accepted normally.
Re: scalar number with preceding 0.
by Limbic~Region (Chancellor) on Jul 26, 2004 at 15:27 UTC
    PerlingTheUK,
    Nothing in your code indicates why a string '0' would show up as unprintable/space. You however have way over complicated things:
    #!/usr/bin/perl use strict; use warnings; while ( <DATA> ) { chomp; print format_time( split " " , $_ ), "\n"; } sub format_time { return sprintf("%.2d:%.2d:%.2d", @_) } __DATA__ 9 12 54 23 8 7

    Cheers - L~R

      In this case I perfectly see that sprintf does the job very well. Only the problem is, that at some other places I will soon have to concatenate strings that cann be only digits, letters, ... a lot of them start with leading 0 that I will need to print out later. I have no clear formatting, at least there are about 12 formats I have seen yet. I do not want to create a regexp for each.
        PerlingTheUK,
        I do not understand what you are asking. If you would like to parse date/time strings that come in different formats, you should have a look at Date::Manip. If you are asking how to do some sort of templating then please try to rephrase your question. Break the problem into small pieces, put them in a logical order, and then present them to us in a digestible manner.

        Cheers - L~R

Re: scalar number with preceding 0.
by Aristotle (Chancellor) on Jul 26, 2004 at 18:12 UTC

    If I run the code you posted verbatim, except for removing the ..., I get 0905 in the first line. The problem in your code is elsewhere, either in that ... which you're hiding, or in another part completely.

    Why would you think a zero character magically turns into a space? Are you sure a zero character was ever added? Try instrumenting your code:

    sub format_time{ my ( $h, $m, $s ) = @_; ... warn "\$h is now '$h', length " . length $h; if ( length( $h ) < 2 ) { warn "going to pad with zero"; $h = "0" . $h; } if ( length( $m ) < 2 ) { $m = "0" . $m; } return $h . $m . $s2; }

    I am almost certain you will find that the space is already there by the time you get to that conditional and that the second message from inside that code block never gets printed.

    Always question your assumptions, and know what your code is doing, instead of programming by coincidence.

    And then, when you've found the problem and taken away its lesson, throw away your code and use sprintf.

    Makeshifts last the longest.

Re: scalar number with preceding 0.
by runrig (Abbot) on Jul 26, 2004 at 18:37 UTC
    Does $h already have a space? When you post sample code, you should include input as well as output. I would print this after assigning the variables to check what's in the variables (update: from a console or into a file, not into a browser from a cgi script):
    print "[$h][$m][$s]\n";
    Also check what's in the variables after any time you modify them. As others have mentioned, zeroes don't just magically become spaces.
Re: scalar number with preceding 0.
by blue_cowdawg (Monsignor) on Jul 26, 2004 at 15:29 UTC

        I basically round the times and want to add a 0 in front of the minutes and hours if they have less than 2 chars anyway.

    errm... what's wrong with:

    : : rest of code before... printf "%0.2d:%0.2d:%0.2d\n",$hour,$min,$sec; : : much handwaving :

Re: scalar number with preceding 0.
by gaal (Parson) on Jul 26, 2004 at 16:00 UTC
    What everyone said (viz, sprintf), but also:
    return $h . $m . $s2;

    What's $s2?

      $s2 is indication for half a second. But that does not have any influence on the result.
        Sounds like you're not using strict... doing that might shed some light on the problem (and indeed on unseen and unforseen ones as well).
Re: scalar number with preceding 0.
by pbeckingham (Parson) on Jul 26, 2004 at 15:29 UTC

    There is a simpler way:

    sub format_time { my ($h, $m, $s) = @_; return sprintf "%02d%02d%02d", $h, $m, $s; }

Re: scalar number with preceding 0.
by gellyfish (Monsignor) on Jul 26, 2004 at 15:29 UTC

    I think you probably want to use sprintf rather than what you are doing now.

    sub format_time { my ( $h, $m, $s) = @; return sprinf "%.02d%.02d%.02d", $h, $m, $s; }

    /J\

Re: scalar number with preceding 0.
by periapt (Hermit) on Jul 27, 2004 at 12:43 UTC
    Have you checked whether they space is already in $h when you get into the sub? If so, your check of the length will not append a "0" (neither will sprintf for that matter. You could check this by adding a debuggin line to the sub print "($h).($m).($s)\n" before your set of if statements.

    Once that issue is resolved, a simple substr('00000000',-$h,-$len) serves for formatting. I usually set the string of zeroes to be as long as I need to cover all formats then set $len to the size I need.

    Alternately, if the possibility of the space cannot be eliminated before the formatting function call, you could use this regex
    $h =~ s/\s*(\d+)/substr(('0' x 8).$1,-$len)/e;

    PJ
    unspoken but ever present -- use strict; use warnings; use diagnostics; (if needed)