This code finds the difference between today and a fixed date.
#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper;
use DateTime ();
use DateTime::Duration ();
use DateTime::Format::Strptime ();
my $date = "23/05-2022";
my $parser = DateTime::Format::Strptime->new(
pattern => '%d/%m-%Y',
time_zone => 'local',
);
$date = $parser->parse_datetime($date);
my $today = DateTime->today(time_zone=>'local');
my $d = DateTime::Duration->new($today - $date);
print Dumper $d->delta_days;
The problem is that is only outputs -22 days.
If I do print Dumper $d;
I can see the -130 months as well.
$VAR1 = bless( {
'seconds' => 0,
'minutes' => 0,
'end_of_month' => 'preserve',
'nanoseconds' => 0,
'days' => -22,
'months' => -130
}, 'DateTime::Duration' );
How do I get it to output the result in days?
Doing
print Dumper $d->delta_days + $d->delta_months*30;
doesn't seam like an elegant solution.
From a quick read of the DateTime module doc, I don't believe that
DateTime::Duration->new($today - $date)
will do what you expect. I believe you need to use
$dur = $today->subtract_datetime($date)
The type of $dur
is not immediately clear from the docs, however.
At first you need to do the correct subtraction. There exists delta_md
, delta_days
, delta_ms
and subtract_datetime_absolute
. Depending on which unit you later want, you need to pick the right subtraction. The problem is that not every unit is convertible later without time_zone information. Thats the reason why you need to pick the correct delta method.
For example a day can have 23 Hours or 24 or 25 Hours, depending on the time zone. Because of that, you need to specify how the subtraction should work. Because you want the days later, the subtraction need to focus on days, rather focus on hours. Don't use the overload feature, because it only does a best fit.
That means you need to do a delta_days
subtraction.
my $dur = $date->delta_days($today);
Now $dur is a DateTime::Duration
object. You need to knew that it always tries to best fit the days, weeks, years, months if possible. That means your days will split in weeks and days. Because this conversion is always a constant.
If you don't want this "best fit" you need to call the in_units
method and convert it only to days.
my $days = $dur->in_units('days');
But like i said before in_units
only can do a conversion where it is possible. A call with in_units('hours')
will not work on this object and just return a zero because you cant convert days to hours. If you want hours for example, you need to do a delta_ms
, and on this object you can call in_units('hours')
The complete example:
#!/usr/bin/env perl
use 5.010;
use strict;
use warnings;
use DateTime;
use DateTime::Format::Strptime;
my $date = "23/05-2022";
my $parser = DateTime::Format::Strptime->new(
pattern => '%d/%m-%Y',
time_zone => 'local',
);
$date = $parser->parse_datetime($date);
my $today = DateTime->new(
day => 1,
month => 7,
year => 2011,
time_zone => 'local'
);
my $dur = $date->delta_days($today);
say "Weeks: ", $dur->weeks;
say "Days: ", $dur->days;
say "Absolute Days: ", $dur->in_units('days');
say "Absolute Hours: ", $date->delta_ms($today)->in_units('hours');
The output of this program is:
Weeks: 568
Days: 3
Absolute Days: 3979
Absolute Hours: 95496
And just for info:
1) You don't need to load DateTime::Duration
its get loaded with DateTime
.
2) You dont need (). These modules are OOP and don't export/import anything.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With