Xi Vix
Xi Vix

Reputation: 1361

Time difference in seconds

In a Perl program I have a variable containing date / time in this format:

Feb 3 12:03:20  

I need to determine if that date is more than x seconds old (based on current time), even if this occurs over midnight (e.g. Feb 3 23:59:00 with current time = Feb 4 00:00:30).

The perl date / time information I've found is mind-boggling. Near as I can tell I need to use Date::Calc, but I am not finding a seconds-delta. Thanks :)

Upvotes: 12

Views: 42408

Answers (6)

Sjoerd Linders
Sjoerd Linders

Reputation: 447

#!/usr/bin/perl

my $Start = time();
sleep 3;
my $End = time();
my $Diff = $End - $Start;

print "Start ".$Start."\n";
print "End ".$End."\n";
print "Diff ".$Diff."\n";

This is a simple way to find the time difference in seconds.

Upvotes: 21

HoldOffHunger
HoldOffHunger

Reputation: 20948

There are some cases where you absolutely cannot import any third party package. One of these instances: online code sandbox websites. After checking ten different Perl sandboxes, I couldn't find a single one that would allow use statements. Unless you full have system-admin permissions to a Perl environment that's entirely at your whim, even testing any of these answers above will be tricky!

Package-Free Solution

Here is a solution that works works without any package dependencies and remains lightweight and simple...

Full Working Demo

sub getTimeDiff {
    my ($times) = @_;
    
    my @times = sort {$a cmp $b} @{$times};
    my ($endhour, $endminute, $endsecond, $starthour, $startminute, $startsecond) = (split(':', $times[0]), split(':', $times[1]));
    my $diff = ($starthour * 60 * 60) + ($startminute * 60) + ($startsecond) - ($endhour * 60 * 60) - ($endminute * 60) - ($endsecond);
    
    return $diff;
}

print(getTimeDiff(["13:00:00", "13:35:17"]));      // output: 2117 (seconds)

Explanation

There are three operations happening here:

  1. Sort the times using alpha cmp sort, so that the endtime is in the [0]'th position and the start time in the [1]'th position.
  2. Split the start/end times into pieces.
  3. Calculate the diff using basic arithmetic.

Avoid Package-Based or CPAN-Based Solutions

Why do it this way? Easy, it's not even 1kb of code. Look at some of the file sizes in these packages! That chews through diskspace and memory! If you have something simple to just calculate the time diff, it might be faster to just use your own function.

Date::Manip FileSizes

What's worse than that? Even understanding how these packages work!

use Date::Manip;
$ret = Date::Manip::DateCalc("13:00:00","13:30:00",0).'';
$ret = Date::Manip::DateCalc("00:00:00", $ret,0).'';
$ret = UnixDate($ret, '%I:%M:%S');
print("Date::Manip Result: " . $ret);

According to Date::Manip, what's the difference between "13:00:00" and "13:30:00"? It should be obvious to everyone!

Date::Manip Result: 12:30:00

So, there are difficulties in these packages with the problem of basic addition. I'm really not sure what else to say.

Upvotes: 0

JRFerguson
JRFerguson

Reputation: 7526

In the spirit of TMTOWTDI, you can leverage the core Time::Piece :

#!/usr/bin/env perl
use strict;
use warnings;
use Time::Piece;
my $when = "@ARGV" or die "'Mon Day HH:MM:SS' expected\n";
my $year = (localtime)[5] + 1900;
my $t = Time::Piece->strptime( $year . q( ) . $when, "%Y %b %d %H:%M:%S" );
print "delta seconds = ", time() - $t->strftime("%s"),"\n";

$ ./mydelta Feb 3 12:03:20

delta seconds = 14553

The current year is assumed and taken from your localtime.

Upvotes: 6

theglauber
theglauber

Reputation: 29675

In perl, there is always more than one way to do something. Here's one which uses only a module that comes standard with Perl:

#! perl -w

use strict;
use Time::Local;

my $d1 = "Feb 3 12:03:20";
my $d2 = "Feb 4 00:00:30";

# Your date formats don't include the year, so
# figure out some kind of default.
use constant Year => 2012;


# Convert your date strings to Unix/perl style time in seconds
# The main problems you have here are:
# * parsing the date formats
# * converting the month string to a number from 1 to 11
sub convert
{
    my $dstring = shift;

    my %m = ( 'Jan' => 0, 'Feb' => 1, 'Mar' => 2, 'Apr' => 3,
            'May' => 4, 'Jun' => 5, 'Jul' => 6, 'Aug' => 7,
            'Sep' => 8, 'Oct' => 9, 'Nov' => 10, 'Dec' => 11 );

    if ($dstring =~ /(\S+)\s+(\d+)\s+(\d{2}):(\d{2}):(\d{2})/)
    {
        my ($month, $day, $h, $m, $s) = ($1, $2, $3, $4, $5);
        my $mnumber = $m{$month}; # production code should handle errors here

        timelocal( $s, $m, $h, $day, $mnumber, Year - 1900 );
    }
    else
    {
        die "Format not recognized: ", $dstring, "\n";
    }
}

my $t1 = convert($d1);
my $t2 = convert($d2);

print "Diff (seconds) = ", $t2 - $t1, "\n";

To make this really production-ready, it needs better handling of the year (for example, what happens when the start date is in December and end date in January?) and better error handling (for example, what happens if the 3-char month abbreviation is mispelled?).

Upvotes: 3

Marius Kjeldahl
Marius Kjeldahl

Reputation: 6824

Assuming you want to use Date::Calc, convert the two values to "time" values with Date_to_Time and subtract the values to get the difference in seconds. But to do this, you need to convert from the strings to YY MM DD hh mm ss values to pass to Date_to_Time first.

Upvotes: 2

vmpstr
vmpstr

Reputation: 5211

There seems to be a convenient Date::Parse. Here's the example:

use Date::Parse;

print str2time ('Feb 3 12:03:20') . "\n";

And here's what it outputs:

$ perl test.pl
1328288600

which is: Fri Feb 3 12:03:20 EST 2012

I'm not sure how decent the parsing is, but it parses your example just fine :)

Upvotes: 9

Related Questions