Beefy Boxes and Bandwidth Generously Provided by pair Networks
Do you know where your variables are?
 
PerlMonks  

More accurate way to calculate Date difference

by Anonymous Monk
on Aug 11, 2018 at 06:24 UTC ( [id://1220223]=perlquestion: print w/replies, xml ) Need Help??

Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

Hi Monks,
I want to check if two given dates have a difference of maximum 6 months. I go about like this:
use Date::Calc qw(:all); use strict; my @data_date_confirm=(); my @data_date_birth=(); my $diab_confirm = '29/08/2013'; my $date_birth = '21/02/2013'; if($diab_confirm=~/(\d+)\/(\d+)\/(\d+)/) { my $day_confirm = $1; my $month_confirm = $2; my $year_confirm = $3; @data_date_confirm = ($year_confirm, $month_confirm, $day_conf +irm); } if($date_birth=~/(\d+)\/(\d+)\/(\d+)/) { my $day_birth = $1; my $month_birth = $2; my $year_birth = $3; @data_date_birth = ($year_birth, $month_birth, $day_birth); } my $dd = Delta_Days(@data_date_birth, @data_date_confirm); my $months_until_confirm = sprintf("%.1f", $dd/30); if($months_until_confirm<=6) { print "They are different by more than 6 months!\n"; }

I realise though that this is not entirely correct, since I divide by 30 days. Is it a way to be more precise?
Thank you!

Replies are listed 'Best First'.
Re: More accurate way to calculate Date difference
by haukex (Archbishop) on Aug 11, 2018 at 08:05 UTC

    It's important to be clear on definitions and provide meaningful examples. For example, sometimes a "month" is defined as exactly 30 days, but since you're asking this question, I'm guessing that's not what you want. For example, using DateTime math:

    2016-01-29 + 30 days = 2016-02-28    2017-01-29 + 30 days = 2017-02-28
    2016-01-30 + 30 days = 2016-02-29    2017-01-30 + 30 days = 2017-03-01
    vs.
    2016-01-29 + 1 month = 2016-02-29    2017-01-29 + 1 month = 2017-03-01
    2016-01-30 + 1 month = 2016-03-01    2017-01-30 + 1 month = 2017-03-02
    

    I would recommend this: First, calculate the "deadline" date by adding your "6 months" to the $date_birth. Then, use the methods provided by the library to see if the $diab_confirm is past that date or not. For example, in Date::Calc that would probably be Add_Delta_YM for the first part, and Date_to_Days or Delta_Days for the second.

    Personally, I like DateTime, and its objects overload the comparison operators:

    use warnings; use strict; use DateTime; use DateTime::Format::Strptime; my $date_birth = '21/02/2013'; my $diab_confirm = '29/08/2013'; my $strp = DateTime::Format::Strptime->new(on_error=>'croak', pattern => '%d/%m/%Y'); my $dt_birth = $strp->parse_datetime($date_birth); my $dt_confirm = $strp->parse_datetime($diab_confirm); print " birth: ", $dt_birth->ymd, "\n"; print " confirm: ", $dt_confirm->ymd, "\n"; my $dt_deadline = $dt_birth->clone->add(months=>6); print "deadline: ", $dt_deadline->ymd, "\n"; if ($dt_confirm > $dt_deadline) { print $dt_confirm->ymd, " > ", $dt_deadline->ymd, "\n"; } else { print $dt_confirm->ymd, " <= ", $dt_deadline->ymd, "\n"; } __END__ birth: 2013-02-21 confirm: 2013-08-29 deadline: 2013-08-21 2013-08-29 > 2013-08-21

    As always, the more test cases the better!

Re: More accurate way to calculate Date difference
by hippo (Bishop) on Aug 11, 2018 at 09:20 UTC

    Room for one more? Here's a generic Time::Piece solution:

    use strict; use warnings; use Time::Piece; use Test::More; my $fmt = '%d/%m/%Y'; my $date = Time::Piece->strptime ('21/02/2013', $fmt); my @within = ('12/08/2013'); my @without = ('29/08/2013'); my $mon = 6; plan tests => @within + @without; for my $other (@within) { ok (within_months ($mon, $date, Time::Piece->strptime ($other, $fm +t)), "$other is within $mon months of $date"); } for my $other (@without) { ok (! within_months ($mon, $date, Time::Piece->strptime ($other, $ +fmt)), "$other is not within $mon months of $date"); } sub within_months { my ($mon, @d) = @_; if ($d[0] > $d[1]) { push @d, shift @d }; my $start = $d[0]->add_months ($mon); return $start > $d[1]; }

    Feel free to expand the @within and @without arrays with more test cases. You can also change $mon to whatever number you require. Time::Piece is in core so there are no extra dependencies needed here.

Re: More accurate way to calculate Date difference
by Athanasius (Archbishop) on Aug 11, 2018 at 07:46 UTC

    Here is one way:

    use strict; use warnings; use DateTime; my $dt1 = DateTime->new ( year => 2013, month => 9, day => 29, ); my $dt2 = DateTime->new ( year => 2013, month => 3, day => 29, ); my $dt3 = DateTime->new ( year => 2013, month => 3, day => 30, ); my $dur1 = $dt2->subtract_datetime($dt1); printf "29/03/2013 to 29/09/2013: %s months\n", $dur1->months; my $dur2 = $dt3->subtract_datetime($dt1); printf "30/03/2013 to 29/09/2013: %s months\n", $dur2->months;

    Output:

    17:44 >perl 1919_SoPW.pl 29/03/2013 to 29/09/2013: 6 months 30/03/2013 to 29/09/2013: 5 months 17:44 >

    Update: Please see the correction by haukex, below.

    Hope that helps,

    Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,

      Unfortunately, one has to be careful with DateTime::Duration objects' accessors: ->month only returns the "months" component of the difference. You usually want ->in_units instead, but note the limitations of conversion - for example, you can't convert a number of months to a number of days without knowing which months we're talking about (and that information is no longer available if we only have a duration), so you have to get both the months and days, and in_units will do the conversion from years to months for you.

      use warnings; use strict; use DateTime; my $dt1 = DateTime->new(year => 2013, month => 10, day => 1); my $dt2 = DateTime->new(year => 2018, month => 3, day => 31); my $dur1 = $dt2->subtract_datetime($dt1); print $dt1->ymd, " to ", $dt2->ymd, ": ", $dur1->months, " months - oops!\n"; my ($days,$months) = $dur1->in_units('days','months'); print $dt1->ymd, " to ", $dt2->ymd, ": ", "$months months, $days days", "\n"; __END__ 2013-10-01 to 2018-03-31: 5 months - oops! 2013-10-01 to 2018-03-31: 53 months, 30 days
      That is great!
      Thank you so much!
Re: More accurate way to calculate Date difference
by choroba (Cardinal) on Aug 11, 2018 at 08:03 UTC
    See a recent question here: Date comparison

    ($q=q:Sq=~/;[c](.)(.)/;chr(-||-|5+lengthSq)`"S|oS2"`map{chr |+ord }map{substrSq`S_+|`|}3E|-|`7**2-3:)=~y+S|`+$1,++print+eval$q,q,a,

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://1220223]
Approved by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others browsing the Monastery: (3)
As of 2024-04-25 12:01 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found