如何在perl中减去日期并将其转换为分钟和小时?

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

每次我试图找出这些日期字符串的区别时,都会出错。我想知道你能不能帮我这个。

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

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

我想将结果转换为分钟和小时。

这两个时间戳只是字符串。为了获得这两个时刻之间的持续时间(“减去”它们),需要从它们构建日期时间对象,在一个知道如何找到它们之间的持续时间的库中。一个不错的选择是 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;
}

此处的硬编码输入时间戳与问题中的不同;这些将使小时+分钟的差异为零,因为它们仅以秒为单位不同! (这是故意的吗?)还可以提交两个时间戳字符串作为该程序的输入。

请注意,通用 duration object 很难转换为任何特定的所需单位

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.

所以上面我使用 delta_ms 因为分钟很容易转换为小时+分钟。正如问题所暗示的那样,秒数被丢弃(如果这实际上是无意的,将它们添加到例程中)。

但对于更一般的用途,可以做到

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)

也可以用核心 Time::Piece 做到这一点

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"; 

这要简单得多,但要注意 Time::Piece.

中偶尔出现的棘手(导致错误)API

请注意,虽然 Time::Piece 是核心、简洁且更轻便(并且正确!),但 DateTime 更全面、更强大,还具有扩展生态系统。

使用 Time::Piece,这是自 2007 年以来 Perl 库的标准部分。

#!/usr/bin/perl

use strict;
use warnings;

use Time::Piece;

# Define the format of your inputs
my $format = '%Y-%m-%d %H:%M:%S';

# Convert your date strings into Time::Piece objects
my $datecreated  = Time::Piece->strptime('2021-09-06 04:52:38', $format);
my $dateresolved = Time::Piece->strptime('2021-09-06 04:52:48', $format);

# Time::Piece objects can be subtracted from each other.
# This gives the elapsed time in seconds.
my $time_elapsed = $dateresolved - $datecreated;

# Do the calculations to displace the elapsed time in hours,
# minutes and seconds.
printf "%02dh:%02dm:%02ds\n",
       $time_elapsed->hours,
       $time_elapsed->minutes % 60,
       $time_elapsed->seconds % 60;