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.
| [reply] [d/l] |
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.
| [reply] [d/l] |
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
| [reply] [d/l] [select] |
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";
| [reply] [d/l] |
> 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.
| [reply] [d/l] [select] |
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. | [reply] [d/l] |