Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does this perl DateTime math produce unexpected results?

#!/usr/bin/perl
use DateTime;

$a = DateTime->new(year=>1952,month=>10,day=>21);
$b = DateTime->new(year=>2015,month=>10,day=>31);

$dif = $b-$a;

print $dif->years() ." ". $dif->months() ." ". $dif->days();
# result: 63 0 3

Where does it get the 3 days from? My expectation is 63 0 10.

#!/usr/bin/perl
use DateTime;

$a = DateTime->new(year=>1952,month=>11,day=>1);
$b = DateTime->new(year=>2015,month=>10,day=>31);

$dif = $b-$a;

print $dif->years() ." ". $dif->months() ." ". $dif->days();
# result 62 11 2

My expectation for this one is 62 11 31 or so.

I am trying to do some basic date of birth to age math. The month and year seem to work as I expect but the day seems unpredictable. I have read the CPAN documentation but I still do not understand.

like image 354
Fletcher Moore Avatar asked Oct 31 '15 22:10

Fletcher Moore


1 Answers

$dif->years, $diff->months and in particular $diff->days do not do what you expect. From the DateTime::Duration documentation...

These methods return numbers indicating how many of the given unit the object represents, after having done a conversion to any larger units. For example, days are first converted to weeks, and then the remainder is returned. These numbers are always positive.

Here's what each method returns:

$dur->years()       == abs( $dur->in_units('years') )
$dur->months()      == abs( ( $dur->in_units( 'months', 'years' ) )[0] )
$dur->weeks()       == abs( $dur->in_units( 'weeks' ) )
$dur->days()        == abs( ( $dur->in_units( 'days', 'weeks' ) )[0] )

If you find this confusing, so do I.

What you want is in_units.

# 63 0 10
say join " ", $dif->in_units('years', 'months', 'days');
like image 167
Schwern Avatar answered Sep 23 '22 02:09

Schwern