Beefy Boxes and Bandwidth Generously Provided by pair Networks
laziness, impatience, and hubris
 
PerlMonks  

localtime parse within hash init

by NetWallah (Canon)
on Nov 04, 2014 at 05:33 UTC ( [id://1105972]=perlquestion: print w/replies, xml ) Need Help??

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

Gentle Monks,

I'm trying to get an "elegant" solution to initializing a hash such that it includes a parsed date (i.e. pieces of the date are easily accessible).

I'd like to do it all within the hash init (no separate statements). I have the following working solution:

perl -E 'my %stuff=(otherinfo=>"this and that", dateinfo=>{local %_, map({()} @_{qw|sec min hour mday mon year wday yday isdst|} =localtime(time)), %_}); say "sec=",$stuff{dateinfo}{sec}, " year=",$stuff{dateinfo}{year}' #-- Output -- #sec=2 year=114
I'm hoping wiser monks could help me get rid of the hack (ab)use of "map", and %_ and make this more "elegant" and/or canonical.

Thank you.

Update: I'm also curious how this would look in perl6. (zip, perhaps ?)

        "You're only given one little spark of madness. You mustn't lose it."         - Robin Williams

Replies are listed 'Best First'.
Re: localtime parse within hash init
by McA (Priest) on Nov 04, 2014 at 06:01 UTC

    Hi NetWallah,

    ...I'm also curious how this would look in perl6. (zip, perhaps ?) ...

    You gave the hint yourself. Do you know zip of List::MoreUtils?

    Regards
    McA

      Stackoverflow to the rescue!.

      This works:

      perl -MList::MoreUtils -E 'my %stuff=(otherinfo=>"this and that", dateinfo=>{List::MoreUtils::zip @{[qw|sec min hour mday mon year wday yday isdst|]} ,@{[localtime(time)]} }); say "sec=",$stuff{dateinfo}{sec}, " year=",$stuff{dateinfo}{year}'
      From the article ....
      ... They technically don't need to be named, just dereferenced. e.g. @$ref and @{qw( foo bar )} work just as well as @a. In other words, it has to start with @ (and not be a slice). (ikegami)

      Update:Loops(++) answered identically, at the same time I discovered this.

              "You're only given one little spark of madness. You mustn't lose it."         - Robin Williams

      Thank you (++) - no - I was not aware of zip/mesh in List::MoreUtil.

      However, my attempt at using it fails:

      perl -MList::MoreUtils -E 'my %stuff=(otherinfo=>"this and that", dateinfo=>{List::MoreUtils::zip qw|sec min hour mday mon year wday yday isdst| ,localtime(time) }); say "sec=",$stuff{dateinfo}{sec}, " year=",$stuff{dateinfo}{year}' Type of arg 1 to List::MoreUtils::mesh must be array (not list) at -e +line 5, near ") }" Type of arg 2 to List::MoreUtils::mesh must be array (not localtime) a +t -e line 5, near ") }" Execution of -e aborted due to compilation errors.
      Any workarounds ? Why does it not like a list ?

              "You're only given one little spark of madness. You mustn't lose it."         - Robin Williams

        zip(@{[qw|sec min hour mday mon year wday yday isdst|]} , @{[localtime +]});
Re: localtime parse within hash init
by roboticus (Chancellor) on Nov 04, 2014 at 11:33 UTC

    NetWallah:

    It may not be particularly elegent, but I'd just create a sub that returns the hash.

    sub date_hash { my ($dtm, $rv) = (shift // time, {}); @{$r}{qw(sec min hour mday mon year wday yday isdst)} = localtime( +$dtm); return $rv; }

    My reasons are:

    • This gives you the opportunity to give it a name that makes your initializer easy to read:
      my %stuff=(otherinfo=>"this and that", dateinfo=>{%{date_hash($aTime)}});
    • I find that when I need something like this in a program, it may start out being needed only once, but frequently gets used a few more times.
    • It moves an ugly bit of code out of the way, usually into a projFooUtils.pm file, which often has a handful of routines simple enough to never have to look at again.

    Update: On the way in to work, I remembered that I *have* a similar function in my MCMUtils.pm package already, with a couple of changes:

    • I can never remember the exact abbreviations to use for the date/time chunks, so I use my 'standard' values: YYYY, YY, MM, DD, hh, mm, ss, dow
    • I go ahead and "fix" the month (+1) and year values (YYYY={year}+1970, YY=({year}+1970)%100).
    • I let the user send in the keys desired. So if they send in YYYY, MM, DD that's all I'll return. But if no keys are sent in, it returns all of 'em. Yeah, it makes it a little overcomplicated, perhaps, but I use it in a good few places.

    I'll try to remember to update this node with the code for that function when I get back home. (It's not in my $work util packages (yet)).

    ...roboticus

    When your only tool is a hammer, all problems look like your thumb.

      thanks roboticus (++).

      That leads to:

      perl -E 'my %stuff=(otherinfo=>"this and that", dateinfo=> sub{ my %r; @r{qw|sec min hour mday mon year wday yday isdst|} =localtime(time); return \%r}->()); say "sec=",$stuff{dateinfo}{sec}, " year=",$stuff{dateinfo}{year}'
      Which works, is pretty decent, and free of external modules.

              "You're only given one little spark of madness. You mustn't lose it."         - Robin Williams

Re: localtime parse within hash init
by Laurent_R (Canon) on Nov 04, 2014 at 07:19 UTC
    The Time::localtime and Time::gmtime modules give you direct access by name to the time components. I can't test right now if they work in your context, but I think they should, since they appear to return a hash or probably rather a blessed reference to a hash.
Re: localtime parse within hash init
by NetWallah (Canon) on Nov 04, 2014 at 18:24 UTC
    FWIW - this is the code I finally settled on ..
    my %opt = ( DEBUG => 0, OTHER_UNRELATED_OPT => "Other values", # snip 8< --- more params here ... LOCALHOST => $ENV{HOSTNAME} || $ENV{COMPUTERNAME} || $E +NV{HOST}, DATEFIELD => sub{ local $_={}; @$_{qw|sec min hour mday mon year wday + yday isdst|} =localtime(time); $_->{year}+=1900; $_->{mon}+=1; $_->{yyyymmdd} = sprintf "%04d-%02d-%0 +2d", @$_{qw|year mon mday|}; $_->{hhmm} = sprintf "%02d:%02d", + @$_{qw|hour min|}; return $_} # end of anon sub ->(), # Call the sub REMOTE_PARAMS => "", );
    Thanks everyone !

            "You're only given one little spark of madness. You mustn't lose it."         - Robin Williams

Re: localtime parse within hash init
by Ultimatt (Acolyte) on Nov 05, 2014 at 22:50 UTC

    Re: what would this look like in Perl6...

    First of all you wouldn't do this in Perl6 if you could help it! You would just use the built in core DateTime object and then use the attributes on that object to get the bits of the date and time you want >;3 If you grab yourself a copy of Rakudo the following works from the command line REPL:

    $ perl6 > my $time = DateTime.new(time) 2014-11-05T22:35:54Z > $time.^methods check-time now clone clone-without-validating Instant posix offset off +set-in-minutes offset-in-hours later earlier truncated-to whole-secon +d in-timezone utc local Date Str IO is-leap-year days-in-month daycou +nt-from-ymd ymd-from-daycount get-daycount day-of-month day-of-week w +eek week-year week-number weekday-of-month day-of-year check-value ch +eck-date truncate-parts new perl gist <anon> <anon> <anon> <anon> <an +on> <anon> <anon> <anon> > $time.^attributes Int $!year Int $!month Int $!day Int $!hour Int $!minute Mu $!second M +u $!timezone Callable &!formatter > say $time.month 11 >

    DateTime.new(time) above is the current local time as an object. Just time on its own gives you an Int as the system epoch timestamp in seconds. Calling ^methods on anything gives you a list of the methods an object has which is useful for picking up Perl6, ^attributes is similarly useful and makes it fairly obvious what you can get at in DateTime.

Re: localtime parse within hash init
by Anonymous Monk on Nov 07, 2014 at 11:48 UTC
    You neglect the Time::Piece core module. Enumerating the accessor names yourself is a code smell.
    perl -MTime::Piece=localtime -E ' my %stuff = ( otherinfo => "this and that", dateinfo => scalar localtime ); say "sec=", $stuff{dateinfo}->sec, "year=", $stuff{dateinfo}->year '
      Excellent ! - thank you. I'll incorporate that in.

              "You're only given one little spark of madness. You mustn't lose it."         - Robin Williams

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others lurking in the Monastery: (3)
As of 2024-03-19 04:32 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found