Beefy Boxes and Bandwidth Generously Provided by pair Networks
Welcome to the Monastery
 
PerlMonks  

Human-readable date format strings

by thewebsi (Scribe)
on Oct 21, 2014 at 02:28 UTC ( [id://1104510]=perlquestion: print w/replies, xml ) Need Help??

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

I'd like to work with human-readable date format strings - ie, allow the user to select the date format for input and output using a human-readable string such as 'yyyy-mm-dd'.

Unfortunately, the popular date manipulation strftime()/strptime() functions from POSIX and Time::Piece use a non-human-friendly '%X' format. In my search, I found Time::Format::time_format(), and this does exactly what I want for output (strftime), but there is no input (strptime) equivalent.

Barring any better options, I'll probably write a regex block to convert format strings from a human-readable format to the POSIX format so I can use the standard functions. Before I embark on that however, does anyone have other suggestions? Thanks.

Edit: To clarify, instead of POSIX::strftime ( '%Y %m %d', localtime() ), I'd like to use SomeModule::SomeFunction ( 'yyyy-mm-dd', localtime() ), as Time::Format::time_format() does, but also need support for strptime().

Replies are listed 'Best First'.
Re: Human-readable date formats
by Loops (Curate) on Oct 21, 2014 at 02:43 UTC

    CPAN has to have a date parser that works better for you than you can manage with regex. Date parsing is seriously thorny territory. Take a look at Date::Manip::Date or DateTime for starters. Maybe you already have and aren't happy with the lack of format control for the parsing; if so i'm not sure what to recommend.

        Well, the DateTime module itself doesn't parse strings, but the DateTime family of modules does include DateTime::Format::ISO8601 and most of the Format modules will both parse to and pretty-print DateTime objects. The ISO8601 standard doesn't allow any old wierdness that someone might choose, but it does include most sensible formats.
        DateTime does say: "This module does not parse dates!" so that's out.

        I use DateTime to parse dates (and times) all the time. However, usually I'm parsing some specific pre-defined format, such as the format used by a particular RDBMS, the format used in email headers, or the format found in Apache log files; there are corresponding DateTime::Format::Foo modules for a wide variety of these.

        General-purpose "whatever format the user types" date parsing is a fundamentally intractable problem, because the user will type junk like "6/8", and without further context there is absolutely no way to know what they mean. The five most likely answers are probably (not necessarily in this order) June of 2008, June 8th of the current year, August 6th of the current year, June 8th in the adjacent year (coming year if it's past June 8th already, previous year otherwise), and August 6th in the adjacent year. When getting date input from users, the only really reasonable approach I've discovered so far is to ask for the year, the month, and the day, each in its own appropriately labeled field.

Re: Human-readable date format strings
by thewebsi (Scribe) on Oct 21, 2014 at 05:28 UTC

    Answering my own question here, this turned out not to be such a big deal. For anyone interested in the future, here is the translate_date_format() function I came up with, and a Test script to demonstrate it:

    #!/usr/bin/perl sub translate_date_format { my @tr = ( 'yyyy' => '%Y', 'yy' => '%y', 'mmmm' => '%B', 'mmm' => '%b', 'mm' => '%m', 'dddd' => '%A', 'ddd' => '%a', 'dd' => '%d', 'd' => '%e', 'HH' => '%H', #(%I if am/pm is specified) 'H' => '%k', #(%l if am/pm is specified) 'MM' => '%M', 'AM' => '%p', 'PM' => '%p', 'am' => '%P', 'pm' => '%P', 'SS' => '%S', ); local $_ = shift; for ( my $i = 0; $i <= $#tr; $i += 2 ) { s/(?<!%)$tr[$i]/$tr[$i+1]/g +; } s/%H(.*?%[pP])/%I$1/g; s/%k(.*?%[pP])/%l$1/g; return ( $_ ); } ### Test ############################################################# +######### use POSIX; use Time::Piece; my @test = ( 'yyyy-mm-dd', 'd/mm/yy', 'H:MM:SSAM', 'HH:MM:SSpm', 'mmm ddd, yy', 'dddd, mmmm dd, yyyy HH:MM:SS', ); foreach ( @test ) { my $tdf = translate_date_format ( $_ ); print "$_ => $tdf\n"; my $date = POSIX::strftime ( $tdf, localtime() ); print " POSIX: $date\n"; my $t = localtime(); my $date = $t->strftime ( $tdf ); print " Time::Piece: $date"; $date = $t->strptime ( $date, $tdf ); print " => $date\n"; }
      • Why use an array and not a hash?
      • You are missing "m" (month, no leading zero - maybe "%e")
      • You are missing "w" (day of week: "%w" or "%u")
      • You are missing "ww" (week: "%V" or "%U")
      • You are missing "M" (minute, no leading zero)
      • You are missing "+hhmm" (time zone: "%z")
      • You are missing "+hh:mm" (time zone: "%:z")
      • You are missing "+hh:mm:ss" (time zone: "%::z")

      In many of these human readable formats, "A" is considered AM/PM

      In some (many?) lower case "h" is considered the shortcut for 12-hour version of "H" (likewise for "hh" vs "HH")

      What do you do with "yyy"? Leave it as is?

      Is having "ZZZ" a suggestion for time zone abbreviation "%Z"?

      Is having "j" or "ddddd" or maybe even "d#" a suggestion for day of year ("%j")?


      Enjoy, Have FUN! H.Merijn
        Why use an array and not a hash?

        Because the order matters. If the regex checked for 'yy' before 'yyyy', then 'yyyy-mm-dd' would translate to '%y%y-%m-%d'.

        You are missing...

        I can only do what the POSIX standard supports. Thanks for the translation suggestions, they are easy enough to add.

        What do you do with "yyy"? Leave it as is?

        Like POSIX::strftime(), anything not recognized as a formatting element is left as-is, yes (although 'yyy' in specific would translate to '%yy'). Unlike strftime(), I didn't add an escape sequence in case you wanted a literal 'yy' in the string. Exercise for the user I guess. :-)

Re: Human-readable date formats
by Anonymous Monk on Oct 21, 2014 at 02:59 UTC

    I'd like to work with human-readable date formats - ie, allow the user to select the date format for input and output using a human-readable string such as 'yyyy-mm-dd'.

    What user where in what context?

    I think that is too ambiguous, its better to provide the human a list of examples, or an interactive program.... or a way to contact a programmer

    OTOH see DateTime::Format::Natural :)

    use a non-human-friendly %X format

    They're made for programmers, who are supposed to make life easier for "humans" :)

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://1104510]
Approved by Athanasius
Front-paged by biohisham
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others browsing the Monastery: (4)
As of 2024-04-16 13:20 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found