2010-06-16 225 views
3

我試圖找出一種方法來計算給定年月至兩位小數的記錄的出生年份 - 在Perl中。從日期計算年的三角洲

爲了說明這個例子,考慮這兩個記錄:

date, age at date 
25 Nov 2005, 74.23 
21 Jan 2007, 75.38 

我想要做的就是根據這些記錄的出生年份 - 它應該是,從理論上講,是一致的。問題是,當我試圖通過計算日期字段中的年份與年齡之間的差異來計算它時,我遇到了四捨五入的錯誤,導致結果看起來錯誤,而實際上卻是錯誤的。

我曾嘗試使用int()或sprintf()的某些「巧妙」組合來圓角,但無濟於事。我看過Date :: Calc,但看不到我可以使用的東西。

p.s.由於許多日期都是1970年以前的日子,所以我不能不幸地使用UNIX時代。

+1

多少天每百個代表什麼? (有幾個答案是可能的。) – ysth 2010-06-16 18:20:48

+0

1970年以前不是問題:Unix時間()是一個有符號整數。 但是,有一個更好的理由不使用它:閏年,閏秒... – dolmen 2010-06-17 15:38:06

回答

4

Perl的gmtimelocaltime功能都沒有問題處理負輸入和日期之前1970年

use Time::Local; 
$time = timegm(0,0,0,25,11-1,2005-1900);   # 25 Nov 2005 
$birthtime = $time - (365.25 * 86400) * 74.23; # ~74.23 years 
print scalar gmtime($birthtime);     # ==> Wed Sep 2 11:49:12 1931 

的實際出生日期可能是通過幾天不同,因爲一年的一個百分之一隻是給你一個分辨率爲3-4天。

+0

謝謝 - 這似乎工作正常。我使用的是Date :: Calc,它似乎在處理1970年以前的時代日期時會遇到問題。 決議不是問題,因爲我只是比較幾年。 – Spiros 2010-06-16 17:08:55

+1

根據你的系統的不同,'gmtime'家族的函數*在1902年或2038年之後可能會遇到問題。如果你的perl是其中一個,並且有可能與百歲老人打交道,那麼你可能想要使用'DateTime'爲了安全。 – hobbs 2010-06-16 21:24:42

6

你試過DateTime?它會處理解析和減法。

+0

感謝您的提示 - 我沒有嘗試過,但我會牢記以備將來參考。 – Spiros 2010-06-16 17:09:15

1

我想第二次Oesor的建議(今天第二次),並重申mobrule的提醒,perl處理負日期。所以DateTime是優選的。

但我想說明,這可以與POSIX::mktime做到:

my ($year1, $mon1, $day1) = qw<1944 7 1>; 
my ($year2, $mon2, $day2) = qw<2006 5 4>; 

my $time1 = POSIX::mktime((0) x 3, $day1, $mon1 - 1, 72); 
my $time2 = POSIX::mktime((0) x 3, $day2, $mon2 - 1, 72); 
my $years = $year2 - $year1 - ($time2 < $time1 ? 1 : 0); 
# 61 years 

需要說明的是,Perl的內部時鐘處理的歷史可以追溯到1902年12月14日(實際上是13日中午之後和在下午6點),之前mktime開始返回undef。因此,對於今天99%的人來說,這可能會有。

毫無意義的瑣事:scalar localtime(0x80000000) : 'Fri Dec 13 15:45:52 1901' < - 這是截止(0x80000000是二進制補碼最小整數)

2

使用日期時間和日期::時間。

當您從DateTime中減去DateTime :: Duration時,會得到另一個DateTime。

use strict; 
use warnings; 
use DateTime::Format::Strptime; 
use DateTime::Duration; 

my $fmt = DateTime::Format::Strptime->new(
    pattern => '%d %b %Y', 
    locale => 'en_US', 
); 

my $start = $fmt->parse_datetime($ARGV[0]); 
my $age = DateTime::Duration->new(years => $ARGV[1]); 

my $birth = $start - $age; 
print $fmt->format_datetime($birth), "\n"; 

這裏是如何調用它的例子:

$ perl birth.pl "25 Nov 2005" 74.23 
25 Sep 1931 
$ perl birth.pl "21 Jan 2007" 75.38 
21 Sep 1931 
+0

Hummm,你正在使用'$ age = DateTime :: Duration-> new(年=> $ ARGV [1]);'和$ ARGV [1]是74.23,但是Date :: Manip的手冊用於new(。 ..)說: 此方法採用參數「年」,「月」,「星期」,「天」,「小時」,「分鐘」,「秒」,「納秒」和「end_of_month」。所有這些除了「end_of_month」都是數字。如果有任何數字是負數,整個持續時間是負數。 **所有數字必須是整數。**使用非整數時您是否看到任何問題? – 2012-04-02 14:27:03