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

I'm basically trying to replace this:
my $sth=$dbh->prepare( "SELECT DATE_FORMAT(NOW(), '%M %D, %Y')"); my $rv=$sth->execute; my ($date) = $sth->fetchrow_array; $sth->finish;
with something that doesn't call the database. it seems a bit silly that this code is:
  1. in a loop
  2. the statement isn't prepared outside of the loop
  3. hits the database multiple times for a date when perl could do it
  4. could at least be prepare_cached
so i started looking at POSIX::strftime. only thing is, i can't find a modifier that will add the ordinal suffix to the day of the month. i've read through the perldoc for POSIX.pm, i've read  man strftime ... i've even done some googling ... nothing.

the database query returns: October 22nd, 2004

what i thought would be the equiv. POSIX compliant format

use POSIX qw( strftime ); my $date = strftime "%B %d, %Y", localtime;
returns: October 22, 2004

can i accomplish the 'suffixing' of the ordinal with the POSIX formats, or should I just handle the date outside of the loop?

Replies are listed 'Best First'.
Re: POSIX strftime format question
by davorg (Chancellor) on Oct 22, 2004 at 10:09 UTC

    Yeah, strftime won't handle that.

    It's simple enough to fix it using Lingua::EN::Number::Ordinate tho'.

    #!/usr/bin/perl use strict; use warnings; use POSIX 'strftime'; use Lingua::EN::Numbers::Ordinate; my $date = strftime '%B %d, %Y', localtime; $date =~ s/(\d+)/ordinate($1)/e; print "$date\n"
    --
    <http://www.dave.org.uk>

    "The first rule of Perl club is you do not talk about Perl club."
    -- Chip Salzenberg

      FYI -- typo in one place ...

      it's "Lingua::EN::Numbers::Ordinate", which you have right in the code snip but wrong in the 'use' part of the note ..

      hrm ... install a new module ( which may come in handy ) or roll 'myself' (meaning steal someone else's rolling)?

      either way, it's not something POSIX does ... which i just needed confirmation on.

      thanks.

Re: POSIX strftime format question
by BUU (Prior) on Oct 22, 2004 at 10:19 UTC
    Heres a nifty sub:
    sub suffer { local $_ = shift; my$suf = 'th'; if( !/1.$/ ) { $suf = 'st' if /1$/; $suf = 'nd' if /2$/; $suf = 'r +d' if /3$/ } return $_.$suf; }
    (Mostly stolen from peterS in #perl at freenode.net)
      Neat. That sounds like something I'd like to play with... Perl Golf, anyone?
      sub suffer { local $_ = shift; return $_ . (/(?<!1)([123])$/ ? (qw(- st nd rd))[$1] : 'th'); }
      Hmm, that's not very compact. But at least, it works. :)
      sub suffer { $_[0].substr("stndrdththththththththththththththththth". "stndrdththththththththththst",2*$_[0]-2,2)}
Re: POSIX strftime format question
by bobf (Monsignor) on Oct 22, 2004 at 16:03 UTC

    For the record, there is also the English_Ordinal function in the Date::Calc module, which can return the ordinal in any one of 11 languages. For that matter, both Date::Calc and Date::Manip have quite a few date-to-text functions. If you're doing a lot of manipulation, you might want to take a peek at them.

    On the other hand, it's not a hard translation to do yourself, and the 3 line subs in the other replies are pretty slick. :)

Re: POSIX strftime format question
by YuckFoo (Abbot) on Oct 22, 2004 at 18:20 UTC
    You can use the %o specification of the Date::Format module.

    perl -MDate::Format -e 'print time2str("%o", 86400);'

    YuckFoost

Re: POSIX strftime format question
by TedPride (Priest) on Oct 22, 2004 at 15:39 UTC
    sub suffer { BEGIN { our %suff = (1,'st', 2,'nd', 3,'rd', 21,'st', 22,'nd', 23, +'rd', 31,'st'); } return $_[0] . ($suff{$_[0]} ? $suff{$_[0]} : 'th'); }
    This takes about 3/8 the time to run at large numbers of iterations as either of the other posted suggestions, though none of the routines take a lot of time to run.