### Problem using DateTime

by zBernie (Novice)
 on Aug 04, 2012 at 04:41 UTC Need Help??
zBernie has asked for the wisdom of the Perl Monks concerning the following question:

I'm trying to calculate the number of years, months, weeks, days, hours, minutes, and seconds which have elapsed since my son's birthday, which was 3/13/12 at 8:16 AM. The script below produces output which is almost correct. One problem is that it does not output the days. Here's the output at the time I ran it:
3 years
4 months
3 weeks
16 hours
16 minutes
13 seconds
The 3 years and 4 months are correct, but 3 weeks does not, and there are no days. What am I doing wrong?

```#!/usr/bin/perl

use strict;
use warnings;
use Data::Dumper;
use DateTime;

\$\ = "\n";

my \$bday = DateTime->new(
year   => 2009,
month  => 3,
day    => 13,
hour   => 8,
minute => 16
);

my \$now = DateTime->now(time_zone  => 'America/New_York');

#print Dumper \$t2;

# subtract_datetime returns a "DateTime::Duration" object
my \$dtd1 = now\$->subtract_datetime(\$bday);

print \$dtd1->years . q{ years}             if \$dtd1->years;
print \$dtd1->months . q{ months}           if \$dtd1->months;
print \$dtd1->weeks . q{ weeks}             if \$dtd1->weeks;
print \$dtd1->days . q{ days}               if \$dtd1->days;
print \$dtd1->hours . q{ hours}             if \$dtd1->hours;
print \$dtd1->minutes . q{ minutes}         if \$dtd1->minutes;
print \$dtd1->seconds . q{ seconds}         if \$dtd1->seconds;
print \$dtd1->nanoseconds . q{ nanoseconds} if \$dtd1->nanoseconds;

Replies are listed 'Best First'.
Re: Problem using DateTime
by Khen1950fx (Canon) on Aug 04, 2012 at 05:29 UTC
This outputs the days:
```#!/usr/bin/perl -l

use strict;
use warnings;
use Data::Dumper;
use DateTime;

my \$bday = DateTime->new(
year       => 2009,
month      => 3,
day        => 13,
hour       => 8,
minute     => 16,
second     => 30,
nanosecond => 0,
time_zone  => 'America/New_York',
);

my \$now = DateTime->now;

my \$dtd1 = \$now->subtract_datetime(\$bday);

print \$dtd1->years       . ' years';
print \$dtd1->months      . ' months';
print \$dtd1->weeks       . ' weeks';
print \$dtd1->days        . ' days';
print \$dtd1->hours       . ' hours';
print \$dtd1->minutes     . ' minutes';
print \$dtd1->seconds     . ' seconds';
print \$dtd1->nanoseconds . ' nanoseconds';
Output:
```3  years
4  months
3  weeks
0  days
18 hours
7  minutes
49 seconds
0  nanoseconds
Re: Problem using DateTime
by tobyink (Abbot) on Aug 04, 2012 at 09:13 UTC

The way we earthlings divide and subdivide our time is inescapably weird. DateTime protects you from some of that weirdness, but as I said, the weirdness is ultimately inescapable.

Run this:

```use 5.010;
use DateTimeX::Auto ':auto';
use DateTime::Format::Human::Duration;

sub saydiff
{
state \$fmt = DateTime::Format::Human::Duration::->new;
say \$fmt->format_duration_between(@_);
}

saydiff('2009-02-12', '2012-02-12');
saydiff('2009-02-12', '2012-08-12');
saydiff('2009-02-12', '2012-08-11');
saydiff('2009-02-11', '2012-08-11');

The first two results should be unsurprising:

```3 years
3 years, 6 months
```

The next one is somewhat more odd:

```3 years, 5 months, 3 weeks, 6 days
```

Huh? 3 years, 5 months takes you to the 12th of July; adding 3 weeks to that takes you to the 2nd of August; and then 6 more days is the 8th of August, which is still three days short!

But then the last result is:

```3 years, 6 months
```

... again. And how did we arrive back at that? By shifting one day at the start of the duration. So we see that actually the third result was not wrong; that there are multiple correct answers!, The DateTime module was just selecting a slightly unintuitive one.

Let's go back to your example. "Now" is 00:32:13 on 4th of August 2012. DateTime claims: 3 years, 4 months, 3 weeks, 16 hours, 16 minutes, 13 seconds.

So let's backtrack 3 years: 00:32:13 on 4th of August 2009.

Backtrack 4 months: 00:32:13 on 4th of April 2009.

Backtrack 3 weeks: 00:32:13 on 14th of March 2009.

Backtrack 16 hours: 08:32:13 on 13th of March 2009.

Backtrack 16 minutes: 08:16:13 on 13th of March 2009.

Backtrack 13 seconds: 08:16:00 on 13th of March 2009.

... which is what you wanted!

So DateTime's result makes perfect sense if you count backwards; just not so much if you count forwards.

perl -E'sub Monkey::do{say\$_,for@_,do{(\$monkey=[caller(0)]->[3])=~s{::}{ }and\$monkey}}"Monkey say"->Monkey::do'
Re: Problem using DateTime
by Anonymous Monk on Aug 04, 2012 at 06:29 UTC

Ah, I should have known! Sometimes I wonder if there isn't a perl
module for turning lead into gold.

-Thanks

Re: Problem using DateTime
by frozenwithjoy (Priest) on Aug 04, 2012 at 06:34 UTC
The slides and the video linked in 980626 are really helpful for learning some DateTime tricks and warnings. (as well as learning DateTime usage, in general.)
Re: Problem using DateTime
by Anonymous Monk on Aug 04, 2012 at 05:32 UTC

Hi,

Have a look at Date::Calc Delta_YMDHMS. It does this exactly.

J.C.

Re: Problem using DateTime
by sundialsvc4 (Abbot) on Aug 04, 2012 at 18:04 UTC

P.S.:   Congratulations, Dad!   Are you getting any sleep yet?   :-)

After three years, one would certainly hope so. Mine were each sleeping through the night from around 6 months old.

Besides which, what makes you think zBernie is a dad? Not all Perl programmers are men.

perl -E'sub Monkey::do{say\$_,for@_,do{(\$monkey=[caller(0)]->[3])=~s{::}{ }and\$monkey}}"Monkey say"->Monkey::do'

Create A New User
Node Status?
node history
Node Type: perlquestion [id://985381]
Approved by Khen1950fx
help
Chatterbox?
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others exploiting the Monastery: (4)
As of 2018-01-18 10:24 GMT
Sections?
Information?
Find Nodes?
Leftovers?
Voting Booth?
How did you see in the new year?

Results (211 votes). Check out past polls.

Notices?