Beefy Boxes and Bandwidth Generously Provided by pair Networks
There's more than one way to do things

DateCalc using Date::Manip

by tsdesai (Acolyte)
on Jan 10, 2017 at 09:38 UTC ( #1179270=perlquestion: print w/replies, xml ) Need Help??

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

Hi all, I have an old perl code running from perl 5 version 12 using DateManip and DateCalc on Solaris which runs as it should. We have recently migrated to linux perl 5 version 16 and the DateCalc function doesn't work at all. I am trying to count days between two dates for example, i have tried to output what are the inputs to the DateCalc function
use Date::Manip; my $dt1='2016080100:00:00'; my $dt2='2016123100:00:00'; my $dtopt= DateCalc($dt1,$dt2); print $dtopt;
The above code outputs 0:0:0:0:6576:0:0 where as the old version on Solaris outputs as +0:0:+21:5:1:0:0 I am expecting the output to be as old version of perl. I know there is some problem with the format but unable to figure it out. I would really appreciate any help. I have tried to use ParseDate,Delta_Format but the result is same. P.S this is not my code i am trying to fix this. Many Thanks, Teju

Replies are listed 'Best First'.
Re: DateCalc using Date::Manip
by hippo (Bishop) on Jan 10, 2017 at 10:28 UTC

       print Delta_Format($dtopt,0,'+%yv:%Mv:+%wv:%dv:%hv:%mv:%sv');

      instead of your print line.

      It's probably not the newer Perl that bites you, but rather the newer Date::Manip module that you are using.
      Try to check what you have in Date::Manip::DM6.

      A bit strange; the raw value that I see for the delta calculated from the date values you provided is 0:0:0:110:0:0:0, which isn't equal with what your systems are giving.

        I have tried what you said and it gives me +0:0:+0:0:3648:0:0
        I think depending upon o or 1 the output changes. I have now tried your same code and I get the same output as you. Many Thanks, T
      Hello, Thank you for the reply. I have tried the code as you suggested. Below is my modification to the code
      my $s2="2016080100:00:00"; my $e1="2016123100:00:00"; my $format = '%dh %hd %hh %ht %yd'; $duyx1 =(DateCalc($s2,$e1)); $duyx1 = Delta_Format($duyx1,'2',$format); print "\nduyx1 = $duyx1\n";
      The output that i get from the code above is 0.00 3648.00 3648.00 3648.00 0.00 But the actual output should be +0:0:+21:5:1:0:0 I am not sure what i missing . Really appreciate all your help. Many Thanks, Teju

        Note that your output string contains seven fields and colons between its values.

        Your $format string contains five placeholders and no colons between them.

        If you want identical values, a first step would be to specify the appropriate output format.

        Also, I think the %dh format is not a valid format specification for Date::Manip::DM5.

Re: DateCalc using Date::Manip
by huck (Prior) on Jan 10, 2017 at 10:51 UTC

    Exact, semi-exact, and approximate calculations An exact calculation is one in which the delta used (or produced) is an exact delta. An exact delta is described in the Date::Manip::Delta manual, but the short explanation is that it is a delta which only involves fields of an exactly known length (hours, minutes, and seconds). Business deltas also include days in the exact part. The value of all other fields in the delta will be zero. ... $mode defaults to "exact".

    Why the mode seems to be different between the versions i cannot say

    A semi-exact calculation is one in which the deltas used (or produced) is a semi-exact delta. This is also described in the Date::Manip::Delta manual, but the short explanation is that it includes days and weeks (for standard calculations) or weeks (for business calculations) in addition to the exact fields.

    Edit to add: Ah the mode change is explained in the reply by SBECK in the post that hippo referenced above, i knew i saw something before but couldnt find it

Re: DateCalc using Date::Manip
by SBECK (Chaplain) on Jan 10, 2017 at 15:26 UTC

    As others have noted, there are several ways to do calculations (exact, approximate, semi-approximate). Unfortunately, Date::Manip::DM6 (which is basically just an interface that is backward compatible with the older versions of Date::Manip) didn't currently support all of them (since they didn't even exist in older versions of Date::Manip).

    The was no reason NOT to support them... I just had never thought to add them (and nobody had requested that). So I just did, and in the next version of Date::Manip, you'll be able to do:

    my $dtopt= DateCalc($dt1,$dt2,'semi');

    and get what you want. However, that won't work in the current version.

    Getting what you want with the current version of Date::Manip::DM6 is harder because in the older module, there were only exact and approximate, and in newer versions there are exact, semi-approximate, and approximate, and it's challenging to get what you want. Really, the best way would be to do that calculation using the OO interface:

    use Date::Manip::Date; my $date1 = new Date::Manip::Date; my $date2 = $date1->new_date(); $date1->parse($dt1); $date2->parse($dt2); my $delt = $date1->calc($date2,'semi'); my $delv = $delt->value(); print "$delv\n";

      Wow, thanks

      But there still is a problem, that is semi-approx, and he wants semi-exact

      use Date::Manip; my $dt1="2016080100:00:00"; my $dt2='2016123100:00:00'; my $date1 = new Date::Manip::Date; my $date2 = $date1->new_date(); $date1->parse($dt1); $date2->parse($dt2); my $delts = $date1->calc($date2,'semi'); my $delte = $date1->calc($date2,'exact'); my $delve=$delte->value(); my $delvs=$delts->value(); sub semi_exact { my $delve=shift; my @parts=split(':',$delve); my $h0=$parts[4]+$parts[3]*24+$parts[2]*7*24; my $w=sprintf('%d',$h0/(7*24)); $h0=$h0-$w*7*24; if ($w<0) {$h0=$h0*-1;} my $d=sprintf('%d',$h0/24); $h0=$h0-$d*24; my $delvse="0:0:$w:$d:$h0:$parts[5]:$parts[6]"; return $delvse; } # semi-exact my $delvse=semi_exact($delve); print 'exact :'.$delve."\n"; print 'semi-approx:'.$delvs."\n"; print 'semi-exact :'.$delvse."\n"; my $fe=DateCalc($dt1,$dt2,0); my $fse=semi_exact($fe); print 'functional semi-exact :'.$fse."\n"; exit;
      exact :0:0:0:0:3649:0:0 semi-approx:0:0:21:5:0:0:0 semi-exact :0:0:21:5:1:0:0 functional semi-exact :0:0:21:5:1:0:0

        I don't have a 'semi-exact' mode in Date::Manip... but what you're really saying is: convert an exact delta to a semi-approximate one.

        This is of course different from coming up with an semi-approximate delta from two dates (which is what I was doing... I should have noticed that it wasn't exactly what the OP was doing, but I got ahead of myself after noticing I couldn't use 'semi' mode in the older DateCalc).

        In any case, you can do the following:

        use Date::Manip; my $dt1='2016080100:00:00'; my $dt2='2016123100:00:00'; my $exact= DateCalc($dt1,$dt2); my $semi = DateCalc($dt1,$dt2,'semi'); print "Exact : $exact\n"; print "Semi : $semi\n"; my $delta = ParseDateDelta($exact,'semi'); print "Exact->Semi: $delta\n"; print "\n"; use Date::Manip::Date; my $date1 = new Date::Manip::Date; my $date2 = $date1->new_date(); $date1->parse($dt1); $date2->parse($dt2); my $delt_x = $date1->calc($date2); my $delt_s = $date1->calc($date2,'semi'); my $val = $delt_x->value(); print "New Exact : $val\n"; $val = $delt_s->value(); print "New Semi : $val\n"; $delt_x->convert('semi'); $val = $delt_x->value(); print "New Ex->Se: $val\n";

        which yields:

        Exact : 0:0:0:0:3649:0:0 Semi : 0:0:21:5:0:0:0 Exact->Semi: 0:0:21:5:1:0:0 New Exact : 0:0:0:0:3649:0:0 New Semi : 0:0:21:5:0:0:0 New Ex->Se: 0:0:21:5:1:0:0

        So you can see how to convert an exact delta to a semi-approximate one using either the old or new interfaces.

        A BIG THANK YOU!!!!! I was able to sort out my problem with your code. Although, I need to make some modification to my code after it does the date calculation(with the code you have given) . I will keep you updated. MANY THANKS!!!!!!:)
Re: DateCalc using Date::Manip
by 1nickt (Canon) on Jan 10, 2017 at 13:00 UTC

    Hi tsdesai

    I am trying to count days between two dates ...

    You can use DateTime's delta_days() method for this.

    $ perl -Mwarnings -Mstrict -ML -E' my $parser = DateTime::Format::Strptime->new(pattern => "%Y%m%d%H:%M:% +S", on_error => "croak"); my $dt1 = $parser->parse_datetime("2016080100:00:00"); my $dt2 = $parser->parse_datetime("2016123100:00:00"); say $dt2->delta_days( $dt1 )->in_units("days"); '
    [ Note that you still have to use in_units() because delta_days() returns a DateTime::Duration object (with all values rolled into a whole number of days). ]

    Hope this helps!

    The way forward always starts with a minimal test.
Re: DateCalc using Date::Manip
by LanX (Sage) on Jan 10, 2017 at 11:23 UTC
    Does the output you show really belong to the displayed code?

    As a side note, you should tell us which versions of Date::Manip you are using.

    Cheers Rolf
    (addicted to the Perl Programming Language and ☆☆☆☆ :)
    Je suis Charlie!

    The delta of the dates is roughly 5 months or 152 days.

    6576 hours are roughly 274 days

    21 month + 5 days are roughly 645 days.


    Just realising this delta format has 7 fields, tried to understand the pod and gave up.


    Aha. .. weeks ?!

    > A delta consists of 7 fields: years, months, weeks, days, hours, minutes, and seconds, usually expressed as a colon-separated string. For example:

      Hi, It makes sense to me what you are saying. But i guess i need to display the output in a different format so it caters for the below output

        did you try

        my $dtopt= DateCalc($dt1,$dt2,1);
        or maybe these will work
        my $dtopt= DateCalc($dt1,$dt2,'semi');
        my $dtopt= DateCalc($dt1,$dt2,'approx');

        You haven't answered my questions.

        A) correct output?

        B) Version numbers

        > so it caters for the below output

        Do you even know what it means?

        Cheers Rolf
        (addicted to the Perl Programming Language and ☆☆☆☆ :)
        Je suis Charlie!

Log In?

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

How do I use this? | Other CB clients
Other Users?
Others about the Monastery: (3)
As of 2023-02-02 02:05 GMT
Find Nodes?
    Voting Booth?
    I prefer not to run the latest version of Perl because:

    Results (15 votes). Check out past polls.