Perl subtract two dates - perl

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;
}

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 convert microseconds since epoch to localtime

In perl, given microseconds since epoch how do I convert to localtime in a format like
my $time = sprintf "%02ld,%02ld,%02ld.%06ld", $hour, $min, $sec, $usec;
Eg: "Input = 1555329743301750 (microseconds since epoch) Output = 070223.301750"
The core Time::Piece can do the conversion, but it doesn't handle subseconds so you'd need to handle those yourself.
use strict;
use warnings;
use Time::Piece;
my $input = '1555329743301750';
my ($sec, $usec) = $input =~ m/^([0-9]*)([0-9]{6})$/;
my $time = localtime($sec);
print $time->strftime('%H%M%S') . ".$usec\n";
Time::Moment provides a nicer option for dealing with subseconds, but needs some help to find the UTC offset for the arbitrary time in system local time, we can use Time::Moment::Role::TimeZone.
use strict;
use warnings;
use Time::Moment;
use Role::Tiny ();
my $input = '1555329743301750';
my $sec = $input / 1000000;
my $class = Role::Tiny->create_class_with_roles('Time::Moment', 'Time::Moment::Role::TimeZone');
my $time = $class->from_epoch($sec, precision => 6)->with_system_offset_same_instant;
print $time->strftime('%H%M%S%6f'), "\n";
Finally, DateTime is a bit heavier but can handle everything naturally, at least to microsecond precision.
use strict;
use warnings;
use DateTime;
my $input = '1555329743301750';
my $sec = $input / 1000000;
my $time = DateTime->from_epoch(epoch => $sec, time_zone => 'local');
print $time->strftime('%H%M%S.%6N'), "\n";
(To avoid possible floating point issues, you could replace my $sec = $input / 1000000 with substr(my $sec = $input, -6, 0, '.') so it's purely a string operation until it goes to the module, if you are sure it will be in that string form - but it's unlikely to be an issue at this scale.)

Comparing date and time and the same time in perl

I want to compare both date and time check if the timestamp from the file I'm going to open will have equal or greater date and time as if the my timestamp which looks like this:
$Date = "20170608";
$Time = "105006";
My main problem is how to do it efficiently possibly without adding perl libraries and how to check it when there's going to be situation of date switching and the hour will be for example 23:59:44
Time::Piece is core in perl, and supports 'strptime'.
#!/usr/bin/env perl
use strict;
use warnings;
use Time::Piece;
my $Date = "20170608";
my $Time = "10506";
my $ts = Time::Piece->strptime( "$Date $Time", "%Y%m%d %H%M%S" );
print $ts, "\n";
print "Delta:", $ts->epoch - time(), "\n";
Was unclear on what time that $Time represented - strptime converts it to 10:50:06, but I'm guessing it might be intended to be 01:05:06?
If so, then zero pad.
$Time = sprintf ( "%06d", $Time );
To read the timestamp from the file metadata, then you need stat:
my $mtime = (stat $filename)[9];

How to get time difference in 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

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.