perl: calculating duration between timestamps - perl

I have a series of string pairs
$str1 = '2016-09-29 10:02:29';
$str2 = '2016-09-29 10:05:45';
the first string is always before the second
I would like to calucate how much seconds have passed between the two timestamps
the above would be 196 seconds
is there a quick way to calculate the difference between two timestamps?
(obsolete) Update: I wrote the following code and i m getting this error
my $format = DateTime::Format::Strptime->new(
format => '%Y-%m-%d %H:%M:%S',
time_zone => 'UTC',
on_error => 'croak',
);
The following parameter was passed in the call to DateTime::Format::Strptime::new but was not listed in the validation options: format
at /usr/software/lib/perl5/site_perl/5.8.8/DateTime/Format/Strptime.pm line 130.
DateTime::Format::Strptime::new(undef, 'format', '%Y-%m-%d %H:%M:%S', 'time_zone', 'UTC', 'on_error', 'croak') called at ./show_startup.pl line 150

Using DateTime (and DateTime::Format::Strptime):
use DateTime::Format::Strptime qw( );
my $str1 = '2016-09-29 10:02:29';
my $str2 = '2016-09-29 10:05:45';
my $format = DateTime::Format::Strptime->new(
pattern => '%Y-%m-%d %H:%M:%S',
time_zone => 'local', # If they are local time timestamps
-or-
time_zone => 'UTC', # If they are UTC timestamps
on_error => 'croak',
);
my $dt1 = $format->parse_datetime($str1);
my $dt2 = $format->parse_datetime($str2);
my $seconds = $dt2->delta_ms($dt1)->in_units('seconds');
Using Time::Piece:
use Time::Piece qw( localtime );
my $str1 = '2016-09-29 10:02:29';
my $str2 = '2016-09-29 10:05:45';
my $format = '%Y-%m-%d %H:%M:%S';
my $t1 = Time::Piece->strptime($str1, $format); # If they are UTC timestamps
my $t2 = Time::Piece->strptime($str2, $format); #
-or-
my $t1 = localtime->strptime($str1, $format); # If they are local time timestamps
my $t2 = localtime->strptime($str2, $format); #
my $seconds = ($t2 - $t1)->seconds;

Here's one way, using the Time::Piece module, which comes with Perl:
use strict;
use warnings;
use Time::Piece;
my $str1 = '2016-09-29 10:02:29';
my $str2 = '2016-09-29 10:05:45';
my $format = '%Y-%m-%d %H:%M:%S';
my $t1 = Time::Piece->strptime($str1, $format);
my $t2 = Time::Piece->strptime($str2, $format);
my $seconds = ($t2 - $t1)->seconds;
print "Result: $seconds\n";
This code doesn't take the local timezone into account, i.e. it assumes the times are in UTC.

Related

How can I change date to swedish time zone in a Perl script?

How can I convert a date in format '20170119121941Z' to Swedish time zone in a Perl script?
My current snippet is:
sub get_Date {
my $content = shift;
my $iso8601 = DateTime::Format::ISO8601 -> new;
my $dt = $iso8601->parse_datetime( $content );
###Set the time zone to "Europe/Stockholm" .
$dt->set_time_zone("Europe/Stockholm");
my $dayofmonth = $dt->strftime("%d");
$dayofmonth =~ s/^0//;
my $hour = $dt->strftime("%I");
$hour =~ s/^0//;
my $ISODate = $dt->strftime("%b " . $dayofmonth . ", %Y, " . $hour . ":%M %p ", localtime(time));
return($ISODate);
}
The output you are getting is
Invalid date format: 20170119121941Z
Your code is failing with that message because 20170119121941Z doesn't match a valid ISO8601 format.
There's also the issue that you used strftime correctly twice, then did something nonsense for the third use.
Solution:
use strict;
use warnings;
use feature qw( say state );
use DateTime::Format::Strptime qw( );
sub localize_dt_str {
my ($dt_str) = #_;
state $format = DateTime::Format::Strptime->new(
pattern => '%Y%m%d%H%M%S%Z',
on_error => 'croak',
);
my $dt = $format->parse_datetime($dt_str);
$dt->set_time_zone('Europe/Stockholm');
return $dt->strftime('%b %e, %Y, %l:%M %p');
}
say localize_dt_str('20170119121941Z'); # Jan 19, 2017, 1:19 PM

Using strptime to parse timestamp relative to the local time

I am trying to do some date calculation relative to the current local time.
For example:
use feature qw(say);
use strict;
use warnings;
use Time::Piece;
my $fmt = '%Y-%m-%d_%H:%M:%S';
my $timestamp = "2015-04-12_11:07:27";
# This gives incorrect $t1 relative to localtime
my $t1 = Time::Piece->strptime( $timestamp, $fmt );
my $t2 = localtime;
say "Local time: " . localtime;
say "Local time epoch: " . time;
say $t1->epoch();
say $t2->epoch();
my $timestamp1 = $t1->strftime( $fmt );
my $timestamp2 = $t2->strftime( $fmt );
say $timestamp1;
say $timestamp2;
my $delta = $t2 - $t1;
say $delta;
A sample output:
Local time: Sun Apr 12 12:21:49 2015
Local time epoch: 1428834109
1428836847
1428834109
2015-04-12_11:07:27
2015-04-12_12:21:49
-2738
Which clearly gives the a wrong time difference of -2738. ( It should be a positive number)
If the date-time you parse has no time zone information, it's assumed to be UTC. You can see this by adding the following two lines in your script:
say "tzo1 = ",$t1->tzoffset;
say "tzo2 = ",$t2->tzoffset;
In Paris, the above outputs the following:
tzo1 = 0
tzo2 = 7200
You can override the default to be the local time zone by using the undocumented feature of using localtime instead of Time::Piece as the invocant.
$ perl -MTime::Piece -E'
say Time::Piece->strptime("2015-04-12_11:07:27", "%Y-%m-%d_%H:%M:%S")->tzoffset;
say localtime ->strptime("2015-04-12_11:07:27", "%Y-%m-%d_%H:%M:%S")->tzoffset;
'
0
7200
Doing that minor change gives the answer you were expecting.
$ perl -MTime::Piece -E'
say localtime->strptime("2015-04-12_11:07:27", "%Y-%m-%d_%H:%M:%S") - localtime;
'
5524
I think this can be done using Date::Time :
use feature qw(say);
use strict;
use warnings;
use DateTime;
use DateTime::Format::Strptime;
use DateTime::Duration;
my $strp = DateTime::Format::Strptime->new(
pattern => '%Y-%m-%d_%H:%M:%S',
time_zone => 'local',
);
my $timestamp = "2015-04-12_11:07:27";
my $dt1 = $strp->parse_datetime( $timestamp );
my $dt2 = DateTime->now();
say $dt2->subtract_datetime_absolute( $dt1 )->seconds();

Perl Past Date How To?

I have a perl script that is getting the current time coming through in a but I am also looking to get the date 45 days prior to the current time as well. Here is what I have:
*already tried using date::calc DHMS which is why the second is formatted the way it is but it keeps returning an error
# get the current time stamp
use POSIX qw( strftime );
my $current_time = strftime("%Y-%m-%d %H:%M:%S", localtime);
print "\n$current_time\n";
# get the date 45 days ago
my $time = strftime("%Y, %m, %d, %H, %M, %S", localtime);
print "\n$time\n\n";
Preferably use DateTime, DateManip, or Date::Calc, but you can also:
use POSIX 'strftime', 'mktime';
my ($second,$minute,$hour,$day,$month,$year) = localtime();
my $time_45_days_ago = mktime($second,$minute,$hour,$day-45,$month,$year);
print strftime("%Y-%m-%d %H:%M:%S", localtime $time_45_days_ago), "\n";
Have you tried DateTime?
my $now = DateTime->now( time_zone => 'local' );
my $a_while_ago = DateTime->now( time_zone => 'local' )->subtract( days => 45 );
print $a_while_ago->strftime("%Y, %m, %d, %H, %M, %S\n");
use DateTime;
my $now = DateTime->now( time_zone=>'local' );
my $then = $now->subtract( days => 45 );
print $then->strftime("%Y, %m, %d, %H, %M, %S");
Set the time_zone, it's important here.
Here's a simple solution using DateTime:
use strict;
use warnings;
use DateTime;
my $forty_five_days_ago = DateTime->now(time_zone=>"local")->subtract(days => 45);
my $output = $forty_five_days_ago->ymd(", ");
$output .= ", " . $forty_five_days_ago->hms(", ");
print "$output\n";

perl date calculation with dates of the format 2012-02-03 00:00:00

I need some help with date calculations in perl with dates for the format "2012-02-03 00:00:00". In particular is there a tool I could use to just increment the days and it switches to month and year correctly? Thanks.
See DateTime.
#!/usr/bin/env perl
use strict; use warnings;
use DateTime;
my $ts = '2012-02-03 00:00:00';
my ($y, $m, $d) = ($ts =~ /([0-9]{4})-([0-9]{2})-([0-9]{2})/);
my $dt = DateTime->new(year => $y, month => $m, day => $d);
$dt->add( months => 2, days => 3 );
print $dt->strftime('%Y-%m-%d %H:%M:%S'), "\n";
It's actually a little cleaner to use a DateTime::Format class, and you get error checking for free.
use DateTime::Format::Strptime qw( );
my $format = DateTime::Format::Strptime->new(
pattern => '%Y-%m-%d %H:%M:%S',
time_zone => 'local',
on_error => 'croak',
);
my $ts = '2012-02-03 00:00:00';
my $dt = $format->parse_datetime($ts);
$dt->add( months => 2, days => 3 );
print $format->format_datetime($dt), "\n";
The Time::Piece module is a standard part of the Perl installation and probably does all that you need.
This program uses your example date and adds two months and three days, then a further 400 days. Two alternative ways of displaying the values are shown
use strict;
use warnings;
use Time::Piece;
use Time::Seconds 'ONE_DAY';
my $format = '%Y-%m-%d %H:%M:%S';
my $dt = Time::Piece->strptime('2012-02-03 00:00:00', $format);
$dt = $dt->add_months(2);
$dt += 3 * ONE_DAY;
print $dt->strftime($format), "\n";
$dt += 400 * ONE_DAY;
printf "%s %s\n", $dt->ymd, $dt->hms;
output
2012-04-06 00:00:00
2013-05-11 00:00:00
This is all perfectly possible within core using the POSIX time-handling functions.
The standard POSIX::mktime function already copes with denormalised values, and can correct for days/months out of range. Additionally, POSIX::strftime actually calls this on the given values before formatting them, so it will adjust correctly.
use POSIX qw( strftime mktime );
use POSIX::strptime qw( strptime );
my $format = "%Y-%m-%d %H:%M:%S";
my #t = strptime( "2012-02-03 00:00:00", $format );
#t = #t[0..5]; # Throw away wday and yday
$t[3] += 3; # mday
$t[4] += 2; # mon
say strftime $format, #t;
$t[3] += 400; # mday
say strftime $format, #t;
Gives
2012-04-06 00:00:00
2013-05-11 00:00:00

yyyymmddhhmmss to YYYY-MM-DD hh:mm:ss in perl?

What is the best way to convert yyyymmddhhmmss to YYYY-MM-DD hh:mm:ss and back in perl?
for example: 20130218165601 to 2013-02-18 16:56:01 and back?
(can https://metacpan.org/module/Rose::DateTime do it)?
without regexp, if possible ;)
A module is overkill for this.
# Packed -> ISO
(my $iso_date = $packed_date) =~
s/^(....)(..)(..)(..)(..)(..)\z/$1-$2-$3 $4:$5:$6/s;
# ISO -> Packed
(my $packed_date = $iso_date) =~
s/^(....)-(..)-(..) (..):(..):(..)\z/$1$2$3$4$5$6/s;
Rose::DateTime cannot parse the "packed" format as intended, but you could use DateTime::Format::Strptime.
use DateTime::Format::Strptime qw( );
my $packed_format = DateTime::Format::Strptime->new(
pattern => '%Y%m%d%H%M%S',
on_error => 'croak',
);
my $iso_format = DateTime::Format::Strptime->new(
pattern => '%Y-%m-%d %H:%M:%S',
on_error => 'croak',
);
# Packed -> ISO
my $iso_date = $iso_format->format_datetime(
$packed_format->parse_datetime($packed_date)
);
# ISO -> Packed
my $packed_date = $packed_format->format_datetime(
$iso_format->parse_datetime($iso_date)
);
Quick solution with sprintf.
my $date = sprintf "%s%s-%s-%s %s:%s:%s", $string =~ /(..)/g;
And back:
my $foo = join '', $date =~ /\d+/g;
without regular expressions, you can just use substr to grab the characters you want:
$year = substr $d, 0, 4;
$month = substr $d, 4, 2;
...
$secs = substr $d, 12, 2;