http://www.perlmonks.org?node_id=988043

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

Perl Monks: I have an issue I have been attempting to resolve, I have a set of timestamps in 2 groups, lets say the following:

Group 1:

2012-08-17 12:00:00
2012-08-17 13:00:00

Group 2:

2012-08-17 09:00:00
2012-08-17 12:30:00

What I need is to be able to compare the differences between the 2 time stamps in each group, and then find the intersect time and duration between the 2 groups. Expected output should be something like:

2012-08-17 12:00:00 for 30 minutes
Any assistance would be greatly appreciated

Replies are listed 'Best First'.
Re: timestamp manipulation and evaluation
by kennethk (Abbot) on Aug 17, 2012 at 17:37 UTC

    What have you tried? What worked? What didn't? Code is always appreciated. See How do I post a question effectively?.

    When I need to do date-based math, I reach for DateTime. Which, in fact, will pretty much do what you need.


    #11929 First ask yourself `How would I do this without a computer?' Then have the computer do it the same way.

Re: timestamp manipulation and evaluation
by Kenosis (Priest) on Aug 17, 2012 at 18:22 UTC

    Consider splitting or regexing the Y,Mo,D,H,M,S out of the two time stamps, and then using Delta_DHMSM from Date::Calc to get the difference between those two stamps.

Re: timestamp manipulation and evaluation
by Kenosis (Priest) on Aug 18, 2012 at 04:12 UTC

    Here's a subroutine that you can send those two time stamps to for the desired output (returns 0 if no intersecting time):

    use Modern::Perl; use Date::Calc qw/ Date_to_Time Time_to_Date /; say intersectingTime( '2012-08-17 12:00:00', '2012-08-17 13:00:00', '2012-08-17 09:00:00', '2012-08-17 12:30:00' ); sub intersectingTime { my ( $s1, $e1, $s2, $e2 ) = map Date_to_Time( /\d+/g ), @_; my $tStart = $s1 > $s2 ? $s1 : $s2; my $tEnd = $e1 < $e2 ? $e1 : $e2; $tEnd <= $tStart ? 0 : sprintf '%4d-%02d-%02d %02d:%02d:%02d for %02d minutes', Time_to_Date( $tStart ), ( $tEnd - $tStart ) / 60; }

    Output:

    2012-08-17 12:00:00 for 30 minutes
Re: timestamp manipulation and evaluation
by Anonymous Monk on Aug 17, 2012 at 19:44 UTC

    cpanp -i DateTime::Duration DateTime::Format::Human::Duration DateTime::Format::Natural

    #!/usr/bin/perl -- use strict; use warnings; use DateTime::Duration; use DateTime::Format::Human::Duration; use DateTime::Format::Natural; @ARGV = ( "last week", "today" ) unless @ARGV; my $dfn = DateTime::Format::Natural->new; my $start = $dfn->parse_datetime(shift); my $end = $dfn->parse_datetime(shift); my $diff = $end - $start; print "$end - $start = ", DateTime::Format::Human::Duration->new->format_duration($diff), "\n" +; __END__ 2012-08-04T00:00:00 - 2012-07-28T00:00:00 = 1 week
      Very nice example of these DateTime modules. I installed them and hope they are useful. But, it doesn't exactly figure the intersecting time of 2 sets of start, end times.

      But here is a way to do it that produces output like he wanted. There are other modules besides DateTime that would provide solutions, Time::Piece (Time::Piece was first released with perl v5.9.5), Date::Parse, Time::Local, and probably others.

      Either set of beg/end times could be switched, ($d1_beg and $d1_end could have been named $d2_beg, $d2_end and vice versa and this method would still be correct.

      Chris

      #!/usr/bin/perl use strict; use warnings; use DateTime::Format::Strptime; use List::Util qw/ maxstr minstr /; # first released with perl v5.7.3 my $d1_beg = '2012-08-17 12:00:00'; my $d1_end = '2012-08-17 13:00:00'; my $d2_beg = '2012-08-17 09:00:00'; my $d2_end = '2012-08-17 12:30:00'; if ($d2_beg ge $d1_end or $d2_end le $d1_beg) { print "No common time\n"; } else { my $start = maxstr($d1_beg, $d2_beg); my $end = minstr($d1_end, $d2_end); my $dt = DateTime::Format::Strptime->new(pattern => "%F %T"); my @dt = map $dt->parse_datetime($_), $start, $end; my $dur = $dt[1]->delta_ms($dt[0])->in_units('minutes'); # duratio +n print "$start for $dur minutes\n"; } __END__ *** prints 2012-08-17 12:00:00 for 30 minutes

      Update: There is a nice discussion here about handling durations with DateTime.