【问题标题】:How to subtract dates in perl and convert it in minutes and hours?如何在 perl 中减去日期并将其转换为分钟和小时?
【发布时间】:2021-09-06 05:03:49
【问题描述】:

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

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

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

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

【问题讨论】:

标签: date perl


【解决方案1】:

这两个时间戳只是字符串。为了及时获得这两个时刻之间的持续时间(“减去”它们),需要在一个知道如何找到它们之间的持续时间的库中从它们构建日期时间对象。一个不错的选择是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 使得转换为任何特定的所需单位变得更加困难

通常不能在秒、分钟、天和月之间转换,所以这个类永远不会这样做。相反,使用所需的单位来创建持续时间,例如通过在 DateTime.pm 对象上调用适当的减法/增量方法。

所以上面我使用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 更加全面和强大,还具有扩展生态系统。

【讨论】:

  • 您好,感谢您的帮助!但是当我打印 $duration 它在 DateTime::Duration=HASH(0x55630e4ca6c8) 我想在几分钟内转换它。
  • @blizzy 是的,我被拉离了这个并且没有完成——现在完成了。查看更新
  • @blizzy 进一步更新
  • 非常感谢您的帮助!我只是想验证我是否可以在几分钟内得到结果?我在想我会有一个: $dateresolved: 2021-09-08 02:29:46 $datecreated: 2021-07-16 05:28:05
  • 您给出的第一个代码很棒,但我可以仅以分钟为单位输出时差吗?忽略时间?
【解决方案2】:

使用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;

【讨论】:

  • 我也可以在几分钟内得到结果吗?就像时差以分钟为单位。我想获得时间差异: $datecreated:2021-07-16 05:28:05 $dateresolved:2021-09-08 02:29:46
  • 当我测试上面的脚本时,它说时间解析错误。
  • @blizzy:不出所料,如果你只想要分钟,你可以使用$time_elapsed->minutes。我不知道你为什么会出错。这对我来说可以。你在解析不同的日期/时间字符串吗?
  • 是的,我正在尝试获取这两个 $datecreated: 2021-07-16 05:28:05 $dateresolved: 2021-09-08 02:29:46 的区别,但它说:错误在 /usr/lib/x86_64-linux-gnu/perl/5.26/Time/Piece.pm 第 481 行解析时间。
  • @blizzy:是的,我的日期格式字符串错误。我有%Y-%d-%m。我刚刚将其更正为%Y-%m-%d
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-27
  • 1970-01-01
  • 2021-12-27
  • 1970-01-01
相关资源
最近更新 更多