Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
154 views
in Technique[技术] by (71.8m points)

How to subtract dates in perl and convert it in minutes and hours?

Every time I tried to find the difference of these date strings, there is an error. I wonder if you could help me this.

my $datecreated = '2021-09-06 04:52:38';
my $dateresolved = '2021-09-06 04:52:48';

my $time_elapsed= $dateresolved - $datecreated;
print $time_elapsed;

And I want to convert the result into minutes and hours.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

These two timestamps are mere strings. In order to get the duration between these two moments in time ("subtract" them) one needs to build date-time objects from them, in a library that knows how to then find duration between them. One good choice is DateTime

use warnings;
use strict;
use feature 'say';

use DateTime; 
use DateTime::Format::Strptime; 

my ($ts1, $ts2) = (@ARGV == 2) 
    ? @ARGV : ('2021-09-05 04:52:38', '2021-09-01 04:52:48');

my $strp = DateTime::Format::Strptime->new(
    pattern => '%F %T', time_zone => 'floating', on_error => 'croak'
);    
my ($dt1, $dt2) = map { $strp->parse_datetime($_) } $ts1, $ts2;

# Get difference in hours and minutes (seconds discarded per question)
my ($hrs, $min) = delta_hm($dt1, $dt2);
say "$hrs hours and $min minutes";

# Or (time-stamp hh:mm in scalar context)
my $ts_hm = delta_hm($dt1, $dt2);
say $ts_hm;

# To get wanted units (hours+minutes here) best use a delta_X
sub delta_hm {
    my ($dt1, $dt2) = @_;
    my ($min, $sec) = $dt1->delta_ms($dt2)->in_units('minutes', 'seconds');
    my $hrs = int( $min / 60 );
    $min = $min % ($hrs*60) if $hrs;

    return (wantarray)    # discard seconds
        ? ($hrs, $min)
        : join ':', map { sprintf "%02d", $_ } $hrs, $min;
}

The hard-coded input time-stamps here are different than the ones in the question; those would make an hour+minute difference a zero, since they differ only in seconds! (Is that intended?) One can also submit two time-stamp strings as input to this program.

Note that a generic duration object makes it harder to convert to any particular desired units

One cannot in general convert between seconds, minutes, days, and months, so this class will never do so. Instead, create the duration with the desired units to begin with, for example by calling the appropriate subtraction/delta method on a DateTime.pm object.

So above I use delta_ms since minutes are easily converted to hours+minutes. Seconds are discarded as the question implies (if that is in fact unintended add them in the routine).

But for more general uses one can do

use DateTime::Duration;

my $dur = $dt1->subtract_datetime($dt2);

# Easy to extract parts of the duration, like
say "Hours: ", $dur->hours, " and minutes: ", $dur->minutes;  # NOT conversion

# This leaves out possible longer units (days, months, years)

Can do this with the core Time::Piece as well

use warnings;
use strict;
use feature 'say';

use Time::Piece;

my ($ts1, $ts2) = (@ARGV) 
    ? @ARGV : ('2021-09-05 04:52:38', '2021-09-01 04:52:48');

my ($dt1, $dt2) = map { Time::Piece->strptime($_, "%Y-%m-%d %T") } $ts1, $ts2; 
# In older module versions the format specifier `%F` (`%Y-%m-%d`) may fail 
# so I spell it out here; the %T (for %H:%M:%S) should always be good
# For local times (not UTC) better use Time::Piece::localtime->strptime

my $delta = $dt1 - $dt2; 
# say $delta->pretty;

my $hrs = int( $delta->hours );  
my $min = int($delta->minutes) - ($hrs//=0)*60;
say "$hrs:$min"; 

This is much simpler, but watch out for occasional tricky (error-inducing) API of Time::Piece.

Note, while Time::Piece is core, succinct, and much lighter (and correct!), the DateTime is far more rounded and powerful, also with an ecosystem of extensions.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

1.4m articles

1.4m replys

5 comments

57.0k users

...