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

I'm trying to make a date script. It works fine, except between 12:00 AM and 1:00 AM it displays PM. Here's the poop:
($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, isdst) = localti +me(time); @days = qw(Sunday Monday Tuesday Wednesday Thursday Friday Saturday); @months = qw(01 02 03 04 05 06 07 08 09 10 11 12); $sec = sprintf ("%02d", $sec); $central_time_min = $min; $central_time_min = sprintf ("%02d", $central_time_min); $mday = sprintf ("%02d", $mday); $year = "02"; $zone = "Central Time"; $central_time_hour = $hour + 1; $ampm = "AM"; if ($central_time_hour > 11) { $ampm = "PM"; } if ($central_time_hour > 12) { $central_time_hour = $central_time_hour - 12; }
Could some kind soul help me please?

Replies are listed 'Best First'.
Re: Morning or Night?
by demerphq (Chancellor) on Jan 12, 2002 at 14:22 UTC
    Hmm. I think you might want to revisit your logic here a bit. Im at a loss as to how you _ever_ get the correct time from this code. In fact the entire thing looks a bit disturbing. (Hardcoded _two_digit_ year!?) I suggest you have a look at the POSIX module and more specifically the strftime() subroutine.

    However if you are as determined to reinvent the wheel as I am on occasion then I will state my concerns. the hour field returned from localtime() is in the range 0..23 yet you add 1 to it before beginning, now perhaps you are doing this to adjust for a timezone, but if you think it through it doesnt work. After the addition the hour field is in the range 1..24, so when exactly will we see 12:30AM? (Never.) UPDATE: Oops. Im not entirely correct here. A more complicated AMPM logic does work, but id still say to follow the advice at the bottom.

    Anyway, perhaps the below will help

    my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, isdst) = loca +ltime(time); my $ampm=$hour>11 ? 'PM' : 'AM'; # day or night $hour%=12; # put it in the range 0..11 $hour=12 unless $hour; # convert 0 to 12 print "$hour$ampm"; # print it out
    Now this will work for the current time zone, adjusting it for a different time zone simply requires adding the appropriate number of seconds to the value returned by time() when calling localtime()
    my $hour_secs = 60*60; my @timeparts = localtime(time()+$hour_secs);
    BTW, you might try writing a loop that goes from 0..23 and then print out the results of your solution for each value.

    Yves / DeMerphq
    --
    When to use Prototypes?

Re: Morning or Night?
by blakem (Monsignor) on Jan 12, 2002 at 13:39 UTC
    A quick fix would be:
    $ampm = "AM"; if ($central_time_hour%24 > 11) { $ampm = "PM"; }
    Though it still looks rather convoluted to me....

    Perhaps something like:

    $ampm = ($central_time_hour%24 > 11) ? "PM" : "AM";
    Might make this one stanza a bit better.

    Update: demerphq caught me moving the bug from midnight to noon... changed constants back to 11 to fix it.

    -Blake

      To expand on blakem's solution, the % 24 is needed to make sure you stay within the confines of a 24 hour clock ... otherwise you end up with a non-existant 25th hour (which is > 12, hence PM :)).

      Unfortunately, setting $ENV{TZ} doesn't appear to be all that portable (works under FreeBSD and prolly the other Unices, but not Windows), otherwise you could simplify all of that code and logic to ...

      use POSIX 'strftime'; my $timezone = 'CST6CDT'; # EST5EDT MST7MDT PST8PDT my $date = do { local $ENV{TZ} = $timezone; strftime( '%y %m %A %I %M %S %p', localtime ); }; my($year,$month,$day,$hour,$mins,$secs,$ampm) = split( ' ', $date );

          --k.


Re: Morning or Night?
by n3dst4 (Scribe) on Jan 12, 2002 at 13:58 UTC
    Funny lookin' bit of script there :-)

    Hmmkay. Line 1: isdst is should be $isdst.
    On line 3: @months = map {sprintf('%02d, $_')} (1..12); would be so much perlier :-)
    Why set $year like that? Does localtime get it wrong? And don't set it to a two-digit string, that's sooo Y2K!
    The AM/PM lines could say $ampm = ($central_time_hour > 12)?'AM':'PM'; Oh, and, $central_time_hour %= 12; for the last bit.

    But as to your actual problem: it doesn't do it to me (at least not when I manually clobber $hour and $min) so it's probably in something you've not shown us here. Try outputting values at each stage. You're aren't doing something surreal like calculating $ampm based on $central_time_hour then outputting just $hour, are you ;-)

    Last but not least, Check Thy System Clock. Make sure it isn't out by 12 hours.

    Good morning! (or is that night-night?)
Re: Morning or Night?
by gt8073a (Hermit) on Jan 12, 2002 at 14:03 UTC

    ... between 12:00 AM and 1:00 AM it displays PM.
    and
    $central_time_hour = $hour + 1

    You have logic problems, others above have explained how to fix it, but here is why it is wrong( or so I think ).

    The "$hour + 1" looks like you are running the script in a time zone 1 hour behind your time.
    so, at 12:01AM your time, it is 11:01PM script time( heh ).
    11:01PM script time means $hour is 23, and $central_time_hour is 24, which is greater then 11.

    Will perl for money
    JJ Knitis
    (901) 756-7693
    gt8073a@industrialmusic.com

      I take that back, they did not give you a fix. try this:

      $ampm = ( $central_time_hour > 11 and $central_time_hour < 24 ) ? 'PM' + : 'AM';

      I think that works properly, though it is is just a hack to cover flawed logic.
      Fixing the flawed logic is left as an exercise for the reader.

      Will perl for money
      JJ Knitis
      (901) 756-7693
      gt8073a@industrialmusic.com

Re: Morning or Night?
by metadoktor (Hermit) on Jan 12, 2002 at 16:05 UTC
    If all you're trying to do is print the current time with "AM" or "PM" attached to the date then you can try this ridiculously simple example (caveat: only works for UNIX or Cygwin on Windows).

    #!/usr/local/bin/perl -w
    use strict;
    
    print `date +"%D %P"`;
    

    Prints out the following:

    01/12/02 am
    

    metadoktor

    "The doktor is in."

      Or better yet, avoid forking `date` by using core perl to do the same thing...
      #!/usr/bin/perl -wT use strict; use POSIX qw(strftime); print strftime("%D %P",localtime);

      -Blake

Re: Morning or Night?
by n4mation (Acolyte) on Jan 12, 2002 at 19:33 UTC
    Thanks for the help! I'll keep my day job!