Beefy Boxes and Bandwidth Generously Provided by pair Networks
XP is just a number
 
PerlMonks  

Time::Piece reversibility

by mla12 (Acolyte)
on Jun 17, 2017 at 21:06 UTC ( #1193021=perlquestion: print w/replies, xml ) Need Help??
mla12 has asked for the wisdom of the Perl Monks concerning the following question:

I'm trying to parse a timestamp with Time::Piece, and then stringify the result back into the original date string.

The timestamp includes the zone. I can do it with Time::Local and it works as expected. But with Time::Piece, no matter what I seem to try, the result is displayed as GMT.

See this test:

#!/usr/bin/env perl use strict; use warnings; use Time::Local; use Time::Piece; my $datestr = '2017-06-19 10:07:42-0700'; print "Original date string: $datestr\n\n"; print "Using Time::Local\n"; my $time = timelocal(42, 7, 10, 19, 6, 2017); print " Epoch seconds: $time\n"; print " CORE::localtime: ", scalar CORE::localtime($time), "\n"; print "\n"; print "Using Time::Piece:\n"; print " strptime as static method:\n"; my $obj = Time::Piece->strptime($datestr, '%Y-%m-%d %H:%M:%S%z'); print " stringified: $obj\n"; print " datetime: ", $obj->datetime, "\n"; print " tzoffset: ", $obj->tzoffset, "\n"; print " hour: ", $obj->hour, "\n"; print " strptime as localtime instance method:\n"; $obj = localtime->strptime($datestr, '%Y-%m-%d %H:%M:%S%z'); print " stringified: $obj\n"; print " datetime: ", $obj->datetime, "\n"; print " tzoffset: ", $obj->tzoffset, "\n"; print " hour: ", $obj->hour, "\n"; print " strptime as gmtime instance method:\n"; $obj = gmtime->strptime($datestr, '%Y-%m-%d %H:%M:%S%z'); print " stringified: $obj\n"; print " datetime: ", $obj->datetime, "\n"; print " tzoffset: ", $obj->tzoffset, "\n"; print " hour: ", $obj->hour, "\n";

For me, that produces:

Original date string: 2017-06-19 10:07:42-0700 Using Time::Local Epoch seconds: 1500484062 CORE::localtime: Wed Jul 19 10:07:42 2017 Using Time::Piece: strptime as static method: stringified: Mon Jun 19 17:07:42 2017 datetime: 2017-06-19T17:07:42 tzoffset: 0 hour: 17 strptime as localtime instance method: stringified: Mon Jun 19 17:07:42 2017 datetime: 2017-06-19T17:07:42 tzoffset: -25200 hour: 17 strptime as gmtime instance method: stringified: Mon Jun 19 17:07:42 2017 datetime: 2017-06-19T17:07:42 tzoffset: 0 hour: 17

The CORE::localtime result is what I want. But how do I get that back out of the Time::Piece instances?

I'm using the latest Time::Piece, 1.31

Replies are listed 'Best First'.
Re: Time::Piece reversibility
by choroba (Chancellor) on Jun 17, 2017 at 21:37 UTC
    See also Time::Piece Bug on my scratchpad. Time::Piece is very lightweight and not suitable for working with timezones, unfortunately.

    ($q=q:Sq=~/;[c](.)(.)/;chr(-||-|5+lengthSq)`"S|oS2"`map{chr |+ord }map{substrSq`S_+|`|}3E|-|`7**2-3:)=~y+S|`+$1,++print+eval$q,q,a,
Re: Time::Piece reversibility
by cguevara (Vicar) on Jun 18, 2017 at 00:54 UTC
    #!/usr/bin/env perl use strict; use warnings; use Test::More ('no_plan'); use Time::Piece; $ENV{'TZ'} = 'America/Los_Angeles'; my $datestr = '2017-06-19 10:07:42-0700'; my $t = Time::Piece->strptime($datestr, '%Y-%m-%d %H:%M:%S%z'); my $u = localtime($t->epoch); is($Time::Piece::VERSION, 1.31); is($t->epoch, 1497892062); is($u->epoch, 1497892062); is($t->tzoffset, 0); is($u->tzoffset, -25200); is($t->strftime, 'Mon, 19 Jun 2017 17:07:42 UTC'); is($u->strftime, 'Mon, 19 Jun 2017 10:07:42 PDT'); is($u->strftime('%Y-%m-%d %H:%M:%S%z'), $datestr);
      Interesting. The last question now is how to get "America/Los_Angeles" from "-0700".

      ($q=q:Sq=~/;[c](.)(.)/;chr(-||-|5+lengthSq)`"S|oS2"`map{chr |+ord }map{substrSq`S_+|`|}3E|-|`7**2-3:)=~y+S|`+$1,++print+eval$q,q,a,

      That's very helpful, @cguevara, thank you.

      So to summarize that result, Time::Piece->strptime always returns a gmtime instance (tzoffset = 0). If you want it in localtime, you need to convert that to a localtime instance. Correct?

      My follow-up question, then, is how to achieve that same result if the time zone is not part of the date string? IOW, I want to parse "2017-06-19 10:07:42" into a localtime Time::Piece instance with epoch seconds of 1497892062 and a tzoffset of -25200.

      I can use Time::Local and do this:

      $ENV{'TZ'} = 'America/Los_Angeles'; my $epoch = timelocal(42,07,10,19,05,2017); print "timelocal epoch: $epoch\n"; print "timelocal date: ", scalar localtime($epoch), "\n";

      Produces:

      timelocal epoch: 1497892062 timelocal date: Mon Jun 19 10:07:42 2017

      But since strptime() always returns gmtime, is there a way to do that with Time::Piece currently? It will be treated as UTC and converting it to a localtime() will offset it by 7 hours (in this case).

      #!/usr/bin/env perl use strict; use warnings; use Time::Local; use Time::Piece; $ENV{'TZ'} = 'America/Los_Angeles'; my $datestr = '2017-06-19 10:07:42'; my $gmt = Time::Piece->strptime($datestr, '%Y-%m-%d %H:%M:%S'); my $local = localtime($gmt->epoch); print "gmt epoch: ", $gmt->epoch, "\n", "local epoch: ", $local->epoch, "\n", "datestr: $datestr\n", "T::P gmt strftime: ", $gmt->strftime, "\n", "T::P local strftime: ", $local->strftime, "\n" ;

      Produces

      gmt epoch: 1497866862 local epoch: 1497866862 datestr: 2017-06-19 10:07:42 T::P gmt strftime: Mon, 19 Jun 2017 10:07:42 UTC T::P local strftime: Mon, 19 Jun 2017 03:07:42 PDT

      Of course you could always append the zone that you want to the date string, but that's cheating ;)

        #!/usr/bin/env perl use strict; use warnings; use Test::More ('no_plan'); use Time::Piece; $ENV{'TZ'} = 'America/Los_Angeles'; my $datestr = '2017-06-19 10:07:42'; my $t = localtime->strptime($datestr, '%Y-%m-%d %H:%M:%S'); is($Time::Piece::VERSION, 1.31); is($t->epoch, 1497892062); is($t->tzoffset, -25200); is($t->strftime, 'Mon, 19 Jun 2017 10:07:42 PDT'); is($t->strftime('%Y-%m-%d %H:%M:%S'), $datestr);
Re: Time::Piece reversibility
by 1nickt (Prior) on Jun 17, 2017 at 21:56 UTC

    It's not in the Perl core, but I suggest installing and getting used to using DateTime and its ecosystem for your date and time processing.

    use strict; use warnings; use feature 'say'; use DateTime::Format::Strptime; my $date = '2017-07-19 10:07:42-0700'; my $parser = DateTime::Format::Strptime->new( pattern => '%F %T%z' ); my $datetime = $parser->parse_datetime( $date ); say $datetime->strftime('%a %b %d %T %Y'); __END__
    Output:
    $ perl 1193021.pl Wed Jul 19 10:07:42 2017

    Hope this helps!


    The way forward always starts with a minimal test.
Re: Time::Piece reversibility
by hippo (Abbot) on Jun 17, 2017 at 22:49 UTC
    I'm using the latest Time::Piece, 1.31

    I'm using 1.31_04 and at least in that, strftime works for me for your second spin (which as the only one using localtime makes sense):

    #!/usr/bin/env perl use strict; use warnings; use Time::Local; use Time::Piece; my $datestr = '2017-06-19 10:07:42-0700'; print "Original date string: $datestr\n\n"; print "Using Time::Local\n"; my $time = timelocal(42, 7, 10, 19, 6, 2017); print " Epoch seconds: $time\n"; print " CORE::localtime: ", scalar CORE::localtime($time), "\n"; print "\n"; print "Using Time::Piece:\n"; print " strptime as static method:\n"; my $obj = Time::Piece->strptime($datestr, '%Y-%m-%d %H:%M:%S%z'); print " stringified: $obj\n"; print " datetime: ", $obj->datetime, "\n"; print " tzoffset: ", $obj->tzoffset, "\n"; print " hour: ", $obj->hour, "\n"; print " strftime: ", $obj->strftime, "\n"; print " strptime as localtime instance method:\n"; $obj = localtime->strptime($datestr, '%Y-%m-%d %H:%M:%S%z'); print " stringified: $obj\n"; print " datetime: ", $obj->datetime, "\n"; print " tzoffset: ", $obj->tzoffset, "\n"; print " hour: ", $obj->hour, "\n"; print " strftime: ", $obj->strftime, "\n"; # Has non-UTC timezone +- yay! print " strptime as gmtime instance method:\n"; $obj = gmtime->strptime($datestr, '%Y-%m-%d %H:%M:%S%z'); print " stringified: $obj\n"; print " datetime: ", $obj->datetime, "\n"; print " tzoffset: ", $obj->tzoffset, "\n"; print " hour: ", $obj->hour, "\n"; print " strftime: ", $obj->strftime, "\n";

    BTW, are you aware that the 2 dates you are using are a month apart?

      I did try _04 too. I hadn't noticed the TZ difference, but it's still showing as 5pm rather than 10am:

      strftime: Mon, 19 Jun 2017 17:07:42 PDT

      And no, I forgot about the month being zero based for the test. Thx.

        it's still showing as 5pm rather than 10am:

        Yes, that's definitely the problem. It seems that localtime is changing the epoch as well as setting the offset so you're always getting back to the same displayed hour when you apply both (and gmtime is of course doing neither). Good spot.

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://1193021]
Approved by 1nickt
Front-paged by 1nickt
help
Chatterbox?
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others about the Monastery: (10)
As of 2017-09-20 12:18 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    During the recent solar eclipse, I:









    Results (236 votes). Check out past polls.

    Notices?