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

I am trying to subtract two different times. I tried to do a regular subtraction of variable. I think it won't work

my $first = "00:00:01:04"; my $last = "00:00:08:861"; my $output = $first-$last;

I am looking to extract each values(hour/min/sec/msec) seperatly after the subraction and assign it to variable and compare with the threshold. Is there any function in perl which does timer subtraction?

Replies are listed 'Best First'.
Re: Timer subtraction (updated)
by haukex (Canon) on Oct 06, 2017 at 04:57 UTC

    I normally use the DateTime family of modules for this kind of thing. It looks like what you have there are not absolute times, but timer durations, in which case you could try working with DateTime::Duration objects. (If you are instead working with absolute times, see here and here for solutions.)

    I looked into how to parse durations, and found DateTime::Format::Duration, but am having trouble getting it to parse milliseconds - I have a suspicion this may be a bug, and will look into this and update my node when I know more (Update: Bug reported.). Until then, parsing the duration manually seems to work, as follows. By the way, is it a typo that your milliseconds in $first only have two digits?

    Update 2018-01-15: I have to withdraw my suggestion for DateTime::Format::Duration for now, the number of unfixed bugs - including the one reported by Cristoforo in the reply - is leading me to believe that the module is currently suffering from too many issues to be "just used". See my reply below for a quick-n-dirty alternative, although unfortunately that doesn't support normalization.

    use warnings; use strict; use DateTime::Duration; use DateTime::Format::Duration; my $first = "00:00:01:04"; my $last = "00:00:08:861"; sub my_parse_duration { my $in = shift; my %t; @t{qw/hours minutes seconds nanoseconds/} = $in=~/\A(\d\d):(\d\d):(\d\d):(\d\d\d?)\z/ or die "failed to parse '$in'"; $t{nanoseconds}*=1000000; # ms->ns return DateTime::Duration->new(%t); } $first = my_parse_duration($first); $last = my_parse_duration($last ); my $fmt_out = DateTime::Format::Duration->new( pattern=>'%H:%M:%S:%3N', normalize=>1 ); print $fmt_out->format_duration($first),"\n"; print $fmt_out->format_duration($last ),"\n"; $last->subtract_duration($first); print $fmt_out->format_duration($last ),"\n"; __END__ 00:00:01:004 00:00:08:861 00:00:07:857
      Hi haukex,

      I was using your code and found a problem with different duration parameters.

      my $first = "01:25:52:421"; my $last = "01:26:29:369";
      For this example the seconds and milliseconds in the $last variable have lesser amounts than in the $first variable. The program hangs and will not complete. It only executes the first two print statements. The result should be 00:00:36:948.

      I don't know what can be done to get the program to run to completion (and execute the third print).

      I've been working on this for several days, reading the docs for DateTime::Format::Duration and can't find the answer there - maybe I don't understand it well.

      Thanks. Format duration is not working for me. In the last 3 print statements you are using format_duration which is not supported. Unfortunately, your code snippet fails. Yes, millisecs specified above was typo

        Format duration is not working for me. In the last 3 print statements you are using format_duration which is not supported. Unfortunately, your code snippet fails.

        The code snippet works fine for me. How does it fail for you? Please see How do I post a question effectively? and I know what I mean. Why don't you? - what are the exact error messages you get? Perhaps you have to install DateTime::Format::Duration?

        Even if not, you can still access the fields of the DateTime::Duration object yourself. This outputs the same thing as my above code:

        sub my_fmt_duration { my @t = shift->in_units('hours','minutes','seconds','nanoseconds') +; $t[3]/=1000000; # ns->ms return sprintf("%02d:%02d:%02d:%03d",@t); } print my_fmt_duration($first),"\n"; print my_fmt_duration($last ),"\n"; $last->subtract_duration($first); print my_fmt_duration($last ),"\n";
Re: Timer subtraction
by Discipulus (Monsignor) on Oct 06, 2017 at 04:38 UTC
    Hello, a fast search return Time::Piece to be agood candidate for such subtraction, but it seems does not handles milliseconds

    # pay attention to MSwin32 doublequotes perl -MTime::Piece -E "$t1=Time::Piece->strptime('23:58:59','%H:%M:%S' +);$t2=Time::Piece->strptime('23:56:58','%H:%M:%S');say $diff=($t1-$t2 +)" 121 # or directly subtracting perl -MTime::Piece -E "say Time::Piece->strptime('23:58:59','%H:%M:%S' +) - Time::Piece->strptime('23:56:58', '%H:%M:%S' )" 121


    PS Time::Hires and it's tv_interval supports millisecnds operations: see Re: time difference in milliseconds

    There are no rules, there are no thumbs..
    Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.
Re: Timer subtraction (UPDATED)
by thanos1983 (Vicar) on Oct 06, 2017 at 04:25 UTC

    Hello Anonymous Monk,

    I think you are looking for How do I find difference between two timestamps?.

    Update: Thanks to the idea of the fellow Monk haukex that you might want to measure the process time of your script between two points. In this case you can use Time::HiRes. If this is the case it can give you accuracy down to microseconds.

    Sample of code below:

    #!/usr/bin/perl use strict; use warnings; use Data::Dumper; use feature 'say'; use Time::HiRes qw(gettimeofday tv_interval); # measure elapsed time say 'Start counting'; my $t0 = [gettimeofday]; # do bunch of stuff here say 'I am doing my things here that I want to know the process time... +'; my $t1 = [gettimeofday]; say 'Finished counting'; print Dumper $t0; print Dumper $t1; my $t0_t1 = tv_interval $t0, $t1; say $t0_t1; my $elapsed = tv_interval ($t0, [gettimeofday]); say $elapsed; # $elapsed = tv_interval ($t0); # equivalent code __END__ $ perl Start counting I am doing my things here that I want to know the process time... Finished counting $VAR1 = [ 1507287063, 951261 ]; $VAR1 = [ 1507287063, 951274 ]; 1.3e-05 8.6e-05

    Hope this helps, BR.

    Seeking for Perl wisdom...on the process of learning...not there...yet!
Re: Timer subtraction
by sundialsvc4 (Abbot) on Oct 06, 2017 at 08:21 UTC

    If we take the OP as literally written:

    my $first = "00:00:01:04"; my $last = "00:00:08:861"; my $output = $first-$last;
    ... the values of both $first and $last are quite-clearly strings.   In order to do arithmetic against them, they must be converted to a numeric form.   There are many, many libraries in the CPAN library that are concerned with time, and some of these are built in to the Core so as to be immediately available without installing.

    For instance, DateTime takes the now-common approach of treating a date/time as a Perl object.   You create one, either specifying a string to be decoded or the individual parts of a time, then you can simply manipulate it using the methods provided.

    In this particular case, where a string-format might not be automagically recognized on its own, you might need to break-apart the four parts of the string (e.g. with split() so that you can instantiate the object with the pieces-of-interest as shown in the documentation for DateTime:

    my $dt = DateTime->new( year => 1966, month => 10, day => 25, hour => 7, minute => 15, second => 47, nanosecond => 500000000, time_zone => 'America/Chicago', );

    You have a rich choice of time-handling modules at your disposal which will take care of all of the niggling problems associated with time encoding/decoding and time-arithmetic.

      Restate things stated already and not answer question answered months ago.... classic pretender