2016-09-14 58 views
1

假設我剛剛跑了10公里,現在我有10毫米的分段時間以MM :: SS的形式出現。我想要一個簡單的方法來加總任意數量的分割時間並對其進行平均。例如,也許我想看看最後5公里時與前5公里相比要快多少(或更慢)。添加MM :: SS時間,將它們分開並打印平均值

我可以通過解析時間,將它們分成幾秒然後將它們轉換回MM :: SS來做到這一點。數學並不難,但我想知道CPAN上的某些東西是否已經以簡單的方式做到了這一點。我第一次嘗試使用DateTime,但由於閏秒,它不會從秒轉換爲分鐘。

要清楚,我不在乎在這方面的閏秒,但我很好奇圖書館是否存在。舉個例子,這是我嘗試過的。

#!/usr/bin/env perl 

use strict; 
use warnings; 
use feature qw(say); 

use DateTime::Format::Duration; 

my $formatter = DateTime::Format::Duration->new(pattern => '%M:%S'); 

my @splits = @ARGV; 
my $split_number = @splits; 

my $total = $formatter->parse_duration(shift @splits); 

foreach my $split (@splits) { 
    $total->add_duration(
     $formatter->parse_duration($split)); 
} 

say 'Total time: ' . join ':', $total->minutes, $total->seconds; 

$total->multiply(1/$split_number); 

say 'Average time: ' . join ':', $total->minutes, $total->seconds; 
say 'Using DateTime::Format::Duration: ' . $formatter->format_duration($total); 

和樣品運行:

$ perl script/add-splits.pl 1:30 2:30 
Total time: 3:60 
Average time: 1.5:30 
Using DateTime::Format::Duration: 01:30 

所以,你可以看到,持續時間對象本身,給了我一個正確的答案,而不是一些人想要破譯。

DateTime :: Format ::持續時間試圖有幫助,但在過程中拋出30秒。

我不是在尋找原始代碼來做到這一點。我感興趣的是CPAN是否已經存在。

+0

有可能在日期時間::格式::持續時間如何彙總秒到幾分鐘......你可以提交一個bug票的錯誤。 – xxfelixxx

+0

@xxfelixxx,謝謝。我和DateTime的作者聊過,他建議實際上不應該支持乘以非整數單位,所以我提交了一個針對DateTime :: Duration的錯誤https://rt.cpan.org/Ticket/Display .html?id = 117866&results = 6ab71e8eea43129a0c4f4c5702e469f5 – oalders

+0

@oalders你能解釋一下嗎?我看到的問題本身不是乘法,而是分鐘不能轉換爲秒,反之亦然。所以'3(min)/ 2'必須返回'1.5'。他們說,在文檔中,'DateTime'和':: Duration'(解釋的鏈接在我的答案中)。我對這個問題感興趣,並搜索了我所知道的或可能找到的所有日期/時間模塊,並且沒有發現任何可以正確執行'mm:ss'的和/ ave的任何內容。 (你的'1:30' +'2:30'對兩者來說都是一個很好的測試案例。) – zdim

回答

1

與此發現的問題CPAN上的確切功能是你想操作時間間隔的字符串。大多數模塊都與這些字符串的上下文有關,使用它們作爲日期時間。所以很難找到簡單地添加mm:ss格式的內容。由於這個任務相當具體,而且寫起來很簡單,爲什麼不把它包裝在你自己的包中呢?

話雖如此,看看下面的代碼片段是否符合你的要求。


這是與芯模塊Time::Piece一個簡單的解決方案。它的確需要數秒的時間來完成數學運算,但是它可以包含在一些子集中,然後也可以很容易地將其擴展用於其他計算。

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

use Time::Piece; 
use POSIX 'strftime'; 
use List::Util 'sum'; 

my @times = @ARGV; 

my $fmt = '%M:%S'; 

my $tot_sec = sum map { Time::Piece->strptime($_, $fmt)->epoch } @times; 

my $ave_sec = sprintf("%.0f", $tot_sec/@times); # round the average 

my ($tot, $ave) = map { strftime $fmt, gmtime $_ } ($tot_sec, $ave_sec); 

say "Total time: $tot"; 
say "Average time: $ave"; 

對於manip_times.pl 2:30 1:30此打印

 
Total time: 04:00 
Average time: 02:00 

我們使用Time::Piecestrptime來獲取對象,然後將其epoch方法返回秒,其相加平均。這將使用strftimePOSIX轉換回mm:ssTime::Piece也有strftime,但要使用它,我們必須有一個對象。

注意Time::Piece確實的直接對象,$t1 - $t2,但不能添加。可以給一個對象添加一個整數(秒),但是,$t1 + 120。另請參閱核心Time::Seconds,這是發行版的一部分。在方法


評論中的問題用

所使用不能在不同的單元之間的轉換的對象DateTime::Duration

參見DateTime.pm文檔的How DateTime Math Works部分獲得更多細節。短期課程:一般不能在幾秒,幾分鐘,幾天和幾個月之間轉換,所以這個班級永遠不會這樣做。

從位進一步下跌的頁面,我們看到的轉換可以做到與相關的那些只是「小時< =>分鐘」和「秒< =>納秒」。原因與閏秒,DST等有關。因此計算必須產生如1.5分鐘的結果。


請注意,Class::Date也看起來適合這些特殊要求。

+0

@oalders我已經更新了我的答案,有了更多評論。 – zdim

0

以下是使用DateTime對象的版本。因爲它不處理日期解析,我們必須拆分字符串自己...

add_splits.pl

#!/usr/bin/env perl 

use strict; 
use warnings; 
use feature qw(say); 

use DateTime; 

my @splits = @ARGV; 
my $split_number = @splits; 

my $fmt = "%M:%S"; 
my $total = DateTime->from_epoch(epoch => 0); 

foreach my $split (@splits) { 
    my ($split_min, $split_sec) = split /:/, $split; 
    $total->add(minutes => $split_min, seconds => $split_sec); 
} 

say 'Total time: ' . $total->strftime($fmt); 

my $avg_seconds = $total->epoch/$split_number; 
my $avg = DateTime->from_epoch(epoch => 0)->add(seconds => $avg_seconds); 

say 'Average time: ' . $avg->strftime($fmt); 

輸出

$ perl add_splits.pl 1:30 2:30 
Total time: 04:00 
Average time: 02:00 
+0

這兩個非常有幫助的答案。我接受了第一個,因爲它是第一個,但這也有助於回答我是否存在現有CPAN模塊的問題。 – oalders

相關問題