How to get time difference in perl? - perl

I have two strings which contain time stamps only and look like this - my $t = "2014-11-28 00:00:00.000"; How do I get the time difference between then in readable time (days, hours, minutes, seconds) and not seconds. I am new and I am facing great difficulty in doing this. Each blog or article is telling me to do different things. Some things can't be done because I don't have the modules. I cannot even install the modules into perl because I have many pearl versions on the computer I am working on. So, cpan > install some::modlue does not help.
Please teach me how to do this. Please try to use core perl. Otherwise I will have to spend more time in installing perl modules into the right perl
I made some code to begin with, but its wrong and useless -
use strict;
use warnings;
use Time::Local;
sub secondsToTime{
my $inSeconds = shift;
my $days = int($inSeconds/(24*60*60));
my $hours = ($inSeconds/(60*60))%24;
my $mins = ($inSeconds/60)%60;
my $sec = $inSeconds%60;
my $time = "$days days, $hours hours, $mins mins, $sec seconds";
return $time;
}
# EXAMPLE timelocal( $sec, $min, $hour, $mday, $mon, $year );
my #today = localtime();
print "#today\n";
my $currentTime = timelocal(#today);
#my #t = (0, 00, 13, 28, 11, 2014);
#$currentTime = timelocal(#t);
my #birthday = (0, 00, 12, 28, 11, 2014);
my $birthTime = timelocal(#birthday);
my $sec = ($currentTime - $birthTime);
my $time = secondsToTime($sec);
print "My age = $time\n";

You don't seem to want to help us understand what it is you need.
This program will print the difference between 2014-11-28T00:00:00.000Z and 2014-11-28T00:00:00.000Z.
use strict;
use warnings;
use Time::Piece;
my $start = '2014-11-28T00:00:00.000Z';
my $end = '2014-11-28T00:00:00.000Z';
print difference($start, $end);
sub difference {
my ($beg, $end) = map Time::Piece->strptime(s/\.\d*Z?\z//r, '%Y-%m-%dT%H:%M:%S'), #_;
($end-$beg)->pretty;
}
output
0 seconds

Related

Get previous hour of UTC/GMT time using Perl

I have a script which will print Start & End time of previous hour of UTC/GMT.
#!/usr/local/bin/perl
use strict;
use warnings;
use POSIX qw(strftime);
my ($tmp_date, $tmp_hour, $Start, $End);
my $date = strftime '%Y-%m-%d', gmtime();
print "Date:$date\n";
my $hour = strftime '%H', gmtime();
print "Hour:$hour\n";
if ($hour == "00"){
$tmp_date = $date-1;
$tmp_hour = "23";
} else {
$tmp_hour = $hour-1;
$tmp_date = $date;
}
$a = length($tmp_hour);
if ($a == 1 ){
$tmp_hour="0".$tmp_hour;
}
$Start = $tmp_date.".".$tmp_hour."00";
$End = $tmp_date.".".$hour."05";
if ($End =~ /0005/){
$tmp_date = `TZ=GMT-12 date +%Y%m%d`;
$End =$tmp_date.".".$hour."05";
}
print "Start:$Start, End:$End\n";
For example, lets say now UTC time is: Wed Jun 10 10:18:57 UTC 2020
This should print Start & End time as 2020-06-10.0900 2020-06-10.1005 respectively.
This script is working as expected. But when Daylight savings happens will there be any impact on fetching Start & End time?
I want experts suggestions how can I avoid unnecessary if statements and achieve it by the use of Perl module itself.
PS: Perl version: v5.10.1. Please suggest Perl modules which comes with standard Perl installation (Ex: POSIX, Time::Local etc.) for solution of above problem.
As you're using gmtime(), any DST changes will have no effect at all.
I'm not sure why your end time ends with '05', I would have thought that the end of the hour comes at '00'.
Here's how I'd write it with Time::Piece and Time::Seconds.
#!/usr/bin/perl
use strict;
use warnings;
use feature 'say';
use Time::Piece;
use Time::Seconds;
my $end = gmtime->truncate(to => 'hour');
my $start = $end - ONE_HOUR;
my $format = '%Y-%m-%d %H:%M:%S';
say 'Start: ', $start->strftime($format);
say 'End: ', $end->strftime($format);
If you really want the end time to be five past the hour, then add this line after the ONE_HOUR line:
$end += (5 * ONE_MINUTE);
You can, of course, use any of the standard strftime() sequences to change the format of the output.

Perl subtract two dates

I am fairly new in Perl.
I am trying to subtract two dates in this format
15.07.16 23:13:34
15.07.16 20:04:24
I know that I have to convert this string in a date object. My problem is I am restricted to the basic perl without installing extra packages. Is there a way to do it?
My Version is v5.8.4 and the output should be 03:09:10.
You say that you're using Perl 5.8.4. You really need to get that updated and get the ability to install CPAN modules.
But, here's a way to do what you want using only core Perl functionality that was available in 5.8.4.
#!/usr/bin/perl
use strict;
use warnings;
use Time::Local;
my $date1 = '15.07.16 23:13:34';
my $date2 = '15.07.16 20:04:24';
my $diff = date2sec($date1) - date2sec($date2);
print secs2duration($diff);
sub date2sec {
my ($date) = #_;
my ($day, $mon, $yr, $hr, $min, $sec) = split(/[. :]/, $date);
# I've assumed that your timestamps are in your local timezone,
# so I've used timelocal() here. If your timestamps are actually
# UTC, you should use timegm() instead.
return timelocal($sec, $min, $hr, $day, $mon-1, 2000 + $yr);
}
sub secs2duration {
my ($secs) = #_;
my $hours = int($secs / (60*60));
$secs %= (60*60);
my $mins = int($secs / 60);
$secs %= 60;
return sprintf '%02d:%02d:%02d', $hours, $mins, $secs;
}

Perl - How to get date of Previous wednesday from the given date without using DateTime

All,
I want to find out the date of previous wednesday from the given date.
Eg. I have date as "20150804" and i would need "20150729".
DateTime is not available and i cannot install it as well.
I looked at few examples but they were using DateTime.
Can you please redirect me where i can get some help.? Thanks.
I am planning to code something like below.
Code:
#!/opt/perl-5.8.0/bin/perl
use warnings;
use strict;
my $dt="20150804";
my $prevWednesday=getPrevWednesday($dt);
sub getPrevWednesday()
{
my $givenDt=shift;
...
}
Another brute force approach, this time using another core module Time::Local.
#!/usr/bin/perl
use warnings;
use strict;
use Time::Local;
sub prev_wednesday {
my $date = shift;
my ($year, $month, $day) = $date =~ /(....)(..)(..)/;
my $time = timelocal(0, 0, 12, $day, $month - 1, $year);
do { $time -= 60 * 60 * 24 } until (localtime $time)[6] == 3; # <- Wednesday
my ($y, $m, $d) = (localtime $time)[5, 4, 3];
return sprintf "%4d%02d%02d\n", 1900 + $y, $m + 1, $d;
}
print $_, ' ', prev_wednesday($_), for qw( 20150804 20150805 20150806
20150101 20000301 20010301 );
Using Time::Piece :
use feature qw(say);
use strict;
use warnings;
use Time::Piece;
use Time::Seconds;
my $str = '20150804';
my $fmt = '%Y%m%d';
my $t = Time::Piece->strptime($str, $fmt);
do {
$t = $t - ONE_DAY;
} until ( $t->day eq 'Wed');
say $t->strftime($fmt);
There's always the brute force approach.
#!/usr/bin/perl
use strict;
use warnings;
use 5.010;
use POSIX 'strftime';
my $ONE_DAY = 24 * 60 * 60;
# Get now
my $time = time;
# Subtract days until you get to a Wednesday
do {
$time -= $ONE_DAY;
} until (localtime($time))[6] == 3;
# Format
say strftime '%Y%m%d', localtime $time;
But if you're working in a Perl environment where you can't install modules from CPAN, then it is always worth working to get that restriction removed. Modern Perl programming is often a case of plumbing together the right series of CPAN modules. If you don't have access to CPAN then you're just making your life much harder than it needs to be.
If you really can't get the restriction lifted, then look for another job. It's not worth dealing with people who impose such pointless restrictions.
Update: Just noticed that you're also using a prehistoric version of Perl. You'll need to remove the use 5.010 and replace the say with print. And brush up your CV :-/
Update 2: choroba's solution is better. It deals with any date in the correct format. Mine just deals with the current date. The advice about fixing your working environment still holds though.
Here is a more elegant solution that does not do bruteforce.
use strict;
use warnings;
use Time::Local 'timelocal';
use POSIX 'strftime';
my $dt = "20150804";
say getPrevWednesday($dt);
# note you do not want () here,
# see http://perldoc.perl.org/perlsub.html#Prototypes
sub getPrevWednesday {
my $givenDt = shift;
# parse the string into a unix timestamp
my ( $year, $month, $day ) = $givenDt =~ /(....)(..)(..)/;
my $timestamp = timelocal( 0, 0, 12, $day, $month - 1, $year );
# get the day of week, ignore the rest
my ( undef, undef, undef, undef, undef, undef, $wday ) =
localtime $timestamp;
# because we start the week with Sunday on day 0
# and to get to the previous Wednesday from Sunday it's
# 4 days (Wednesday is 3) we can add 4 to the
# number of this day, divide by 7, take the leftover (modulo)
# and then subtract that many days
# (86_400 is one day in seconds)
# v- -6 ------
# 6 % 7 = 6
# +4 -----v
# v
# 0 1 2 3 4 5 6 0 1 2 3 4 5 6
# S M T W T F S S M T W T F S
my $prev_wed = $timestamp - ( ( $wday + 4 ) % 7 * 86_400 );
# go one week back if we got the same day
$prev_wed -= ( 7 * 86_400 ) if $prev_wed == $timestamp;
# debug output
warn "in: " . localtime($timestamp) . "\n";
warn "out: " . localtime($prev_wed) . "\n\n";
# put it back into your format
return strftime('%Y%m%d', localtime $timestamp);
}
Output:
# STDOUT
20150804
# STDERR
in: Tue Aug 4 12:00:00 2015
out: Wed Jul 29 12:00:00 2015

Substract 15 Minutes from time using Perl

I thought this was going to be very simple but I am really out of options now. I want to substract 15 minutes from a given time.
Example
My time is 15:04 I want to substract 15 minutes to be 14:49. I have searched for solutions on the internet but there is no perl module that can help me out.
You can use DateTime:
my $dt = DateTime->new(
year => 1,
month => 1,
day => 1,
hour => 15,
minute => 4,
);
$dt->subtract(minutes => 15);
printf "%d:%d\n", $dt->hour, $dt->minute; # prints 14:49
Well it all depends on how your time is stored. I prefer to use a time_t as returned by the time built in.
my $now = time();
my $before1 = $now - (15*60); # 15 minutes ago
my $before2 = $now - (3*60*60); # 3 hours ago
my $before3 = $now - (2*24*60*60); # 2 days ago
For output I use the POSIX module
print POSIX::strftime( '%Y-%m-%d %T', localtime($before1) );
perl -MClass::Date -e 'my $d=Class::Date->new("2011-07-13 15:04:00"); my $d2 = $d-"15m"; print $d2, "\n";'
Output:
2011-07-13 14:49:00
Try using Date::Calc
use Date::Calc qw(Add_Delta_DHMS);
($year2, $month2, $day2, $h2, $m2, $s2) =
Add_Delta_DHMS( $year, $month, $day, $hour, $minute, $second, $days_offset, $hour_offset, $minute_offset, $second_offset );
($y,$m,$d,$H,$M,$S) = Add_Delta_DHMS(Today_and_Now(), 0, 0, -15, 0);
convert the time to unix time, for example the current time: $unixtime = time(); then subtract 15*60 from it then convert to a nice string with something like
sub display_time {
my ($sec,$min,$hour,$mday,$mon,$year,undef,undef,undef) = localtime(time);
$year += 1900;
$mon += 1;
return "$year.".sprintf("%02d.%02d %02d:%02d:%02d",$mon,$mday,$hour,$min,$sec);
}
You can use the below sub-routine if you are only concerned about time not date:
sub subTime{
my ($time) = #_;
my #splittime = split(':', $time);
my $hour = $splittime[0];
my $min = $splittime[1];
if($min < 15){
$min=($min+60)-15;
$hour-=1;
}
else{
$min = $min-15;
}
return "$hour:$min";
}
Disclamer: This was the solution OP used, he mentioned it in comments in above answer (in #eugene's answer).

How do I convert local time to a Unix timestamp in Perl?

For example: from date: 10/02/2010
How do I convert an equal timestamp for 10/02/2010 00:00:00 in Perl?
I can't use local time or time .. is there another way to achieve this?
You can use the Time::Local core module:
use Time::Local 'timelocal';
my ($d, $m, $y) = split '/', '10/02/2010';
my $time = timelocal(0, 0, 0, $d, $m-1, $y);
Note that the month argument for timelocal() is in the range 0..11.
Without localtime():
use Time::Local;
$time = timelocal($sec, $min, $hour, $mday, $mon, $year);
(See perldoc.)
A standard way would be something like:
use POSIX;
use strict;
use warnings;
my $sec = 0;
my $min = 0;
my $hour = 0;
my $day = 10;
my $mon = 2 - 1;
my $year = 2010 - 1900;
my $wday = 0;
my $yday = 0;
my $unixtime = mktime ($sec, $min, $hour, $day, $mon, $year, $wday, $yday);
print "$unixtime\n";
my $readable_time = localtime($unixtime);
print "$readable_time\n"
(From Converting Unix time and readable time with Perl)
You could use Date::Parse:
use Date::Parse;
print str2time('10/02/2010 00:00:00');
On my machine this prints 1285970400, which corresponds to October 2nd, 2010 (I live in +1 GMT with +1 Wintertime.)
I think you want the built-in module Time::Local.
The DateTime module should be helpful here. In particular, I believe the DateTime::Format::Natural module can parse a user-supplied date string. From there, you have a DateTime object and can print it out or transform it as you like.
Depending on where your initial date is coming from you might be able to parse it using
Date::Manip
and calling
ParseDate("10/02/2010")
You can then take that output and convert it into whatever format you wish.