The POSIX's strftime
Returns the string.
and you can't conveniently subtract hours from a string.†
Instead, use a library for date-time processing for manipulation, and then format with strftime
An example with Time::Piece
perl -MTime::Piece -MTime::Seconds -wE'
$t = (localtime) - 12*ONE_HOUR;
say $t->strftime("%m/%d/%Y %H:%M")'
The Time::Seconds comes along with Time::Piece
, for various datetime computations.
While Time::Piece
is core and good and well known it does come with subtleties and limitations, and for more involved work I'd recommend the all-knowing (and big and heavy) DateTime
perl -MDateTime -wE'
$t = DateTime->now(time_zone => "local")->subtract(hours => 12);
say $t->strftime("%m/%d/%Y %H:%M")'
I think it's worth emphasizing that this module can do practically everything with datetimes.
As a note, keep in mind the issues that Daylight-Saving Time changes bring. Between miraculous jumps of the clock and occasional non-existing hours there may be unpleasant surprises, albeit rarely (an example).
Here is a program provided by ikegami to test for the coming DST (Mar 08, 2am -> 3am)
use strict;
use warnings;
use DateTime qw( );
use POSIX qw( strftime );
use Time::Piece qw( localtime );
use Time::Seconds qw( ONE_HOUR );
my $epoch = 1583683200; # 2020-03-08T12:00:00
CORE::say
for
DateTime->from_epoch( epoch => $epoch, time_zone => $ENV{TZ} )
->subtract( hours => 12 ),
strftime("%FT%T", localtime($epoch - 12*60*60)),
( localtime($epoch) - 12*ONE_HOUR )->strftime("%FT%T");
Then set TZ
environment variable and run it
TZ=America/New_York perl test_DST.pl
(in bash, while in tcsh it's setenv TZ "America/New_York"; perl test_DST.pl
)
The output
2020-03-07T23:00:00
2020-03-07T23:00:00
2020-03-07T23:00:00
† A function with that name exists in many environments and always returns a formatted string.