Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
588 views
in Technique[技术] by (71.8m points)

perl - How to make DateTime::Duration output only in days?

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.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...