http://qs1969.pair.com?node_id=11144395

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

Hi

I have a date in a string, like:

my $date = 'Sat Jun  4 22:47:31 2022';

This is not a DateTime object. I need to change the timezone of this date by reducing it of 2h. Any suggestion?

Replies are listed 'Best First'.
Re: change hour in timestamp
by 1nickt (Canon) on Jun 04, 2022 at 21:31 UTC

    Hi,

    I suggest to use a parser to parse your string into a DateTime object. I also suggest to handle time zones properly and not just by subtracting a value from the hours. What will happen when you try that and the time is earlier than 02:00 ?

    use strict; use warnings; use feature 'say'; use DateTime::Format::Strptime; my $string = 'Sat Jun 4 01:47:31 2022'; my $parser = DateTime::Format::Strptime->new( pattern => '%a %b %d %T %Y', locale => 'en_US', time_zone => 'America/New_York', on_error => 'croak', ); my $datetime = $parser->parse_datetime($string); $datetime->set_time_zone('America/Denver'); say $datetime->strftime('%a %b %d %T %Y'); __END__

    Hope this helps!


    The way forward always starts with a minimal test.
Re: change hour in timestamp
by johngg (Canon) on Jun 04, 2022 at 22:15 UTC
    The Time::Piece module, along with its associated Time::Seconds module for date calculations, is core.

    johngg@abouriou:~/perl/Monks$ perl -Mstrict -Mwarnings -MTime::Piece - +MTime::Seconds -E 'say q{}; my $date = q{Sat Jun 4 22:47:31 2022}; my $tp = Time::Piece->strptime( $date, q{%a %b %d %T %Y} ); $tp -= ONE_HOUR; $tp -= ONE_HOUR; say $tp->strftime();' Sat, 04 Jun 2022 20:47:31 UTC

    I hope that this is helpful.

    Cheers,

    JohnGG

      G'day JohnGG,

      ++ Upon reading the OP, I immediately thought of Time::Piece; then, after scrolling through the posts, I saw you'd used this already.

      If I may, some minor improvements:

      • Instead of decrementing $tp in two statements, you can do that in one: "$tp -= 2 * ONE_HOUR".
      • Your output has a slightly different format to the OP's input: comma after day and introduced timezone. You can mostly fix that by using the same date format for the input and output.
        Update: On rereading, I also see the month name and day are swapped as are the time and year. The suggested fix handles both of those cases also.
      • If the leading zero on the month nameday is a problem for the OP, you can fix that with sprintf. I added a "$tp += 6 * ONE_DAY" to test that.
        • Checking `man strptime` on my Cygwin platform, I see %d gives a two-digit string, padded with a zero for a single-digit month day. I couldn't find a format for that which doesn't pad with a zero. Assuming I didn't simply miss it, if one exists on another OS, it may not be portable.

      Here's the updated code:

      my $date = q{Sat Jun 4 22:47:31 2022}; my $fmt_t = q{%a %b %d %T %Y}; my $fmt_s = q{%s %s %2d %s %d}; my $tp = Time::Piece->strptime($date, $fmt_t); $tp -= 2 * ONE_HOUR; say sprintf $fmt_s, split q{ }, $tp->strftime($fmt_t); $tp += 6 * ONE_DAY; say sprintf $fmt_s, split q{ }, $tp->strftime($fmt_t);

      which outputs:

      Sat Jun 4 20:47:31 2022 Fri Jun 10 20:47:31 2022

      — Ken

Re: change hour in timestamp
by NERDVANA (Deacon) on Jun 05, 2022 at 14:14 UTC
    My first (and usually last) stop for all date parsing is DateTime::Format::Flexible. It gets this one just fine:

    use DateTime::Format::Flexible; sub date { DateTime::Format::Flexible->parse_datetime(shift); } my $d= date('Sat Jun 4 22:47:31 2022'); $d->set_time_zone('+0200')->set_time_zone('UTC'); print "$d\n";
Re: change hour in timestamp
by LanX (Saint) on Jun 04, 2022 at 21:55 UTC
    > This is not a DateTime object.

    DateTime says

      Parsing Dates

      This module does not parse dates! That means there is no constructor to which you can pass things like "March 3, 1970 12:34".

      Instead, take a look at the various DateTime::Format::* modules on CPAN. These parse all sorts of different date formats, and you're bound to find something that can handle your particular needs.

    I searched around in metacpan and found Date::Parse and the Synopsis seems to do the job well, at least for epoch

    use strict; use warnings; use Data::Dump qw/pp dd/; use Date::Parse; use DateTime; pp my $date = 'Sat Jun 4 22:47:31 2022'; pp my $time = str2time($date); pp my ($ss,$mm,$hh,$day,$month,$year,$zone) = strptime($date); my $dt = DateTime->from_epoch ( epoch => $time, time_zone => 'UTC', # fill in your timezone ); print $dt;

    "Sat Jun 4 22:47:31 2022" 1654375651 (31, 47, 22, 4, 5, 122, undef) 2022-06-04T20:47:31

    Other modules - especially the one suggested by 1nickt - might be better, I just wanted to demonstrate how to solve it by yourself.

    Cheers Rolf
    (addicted to the Perl Programming Language :)
    Wikisyntax for the Monastery

Re: change hour in timestamp
by Anonymous Monk on Jun 05, 2022 at 09:26 UTC

    Thank you for all the interesting answers. Another easy approach to achieve my OP:

    use strict; use warnings; use Time::Piece; my $date = "Sat Jun 4 22:47:31 2022 +0200"; my $fmt = '%a %b %d %T %Y %z'; my $tp = Time::Piece->strptime($date, $fmt); print $tp;

    I agree with the mention that I should work with timezone though.