1

I im using perl strftime for (datetime now)

perl -MPOSIX -e 'print POSIX::strftime("%m/%d/%Y %H:%M", localtime());'

i want to minus datetime now by 12 hour

Example OUTPUT: 2/7/2020 1:00 to 2/6/2020 13:00 <- minus 12 hours only

Please help to solve this problem by using mentioned code

zdim
  • 64,580
  • 5
  • 52
  • 81
Drin
  • 21
  • 4

2 Answers2

5

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.

zdim
  • 64,580
  • 5
  • 52
  • 81
  • @ikegami Ah, great! Interesting that all (three methods shown on this page -- `localtime` tweak and two in this answer) "work" the same. I don't understand though how it winds up (down, rather) at 11pm... (I think it'd be a good idea to include that code of yours in this answer) – zdim Feb 07 '20 at 07:37
  • America/New_York uses EDT for the start ts, but EST for the earlier ts. 12 hours before noon EDT is midnight EDT or 11pm EST. – ikegami Feb 07 '20 at 07:47
  • @ikegami ugh, right. thank you. i've added your program to the post – zdim Feb 07 '20 at 08:12
1

Using Time::Moment and Time::Moment::Role::TimeZone (to correct for DST changes):

perl -MTime::Moment -MWith::Roles -E'say Time::Moment->with::roles("+TimeZone")->now
  ->minus_hours(12)->with_system_offset_same_instant->strftime("%m/%d/%Y %H:%M")'
Grinnz
  • 9,093
  • 11
  • 18