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];
Related
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.
use Date::Calc qw(:all);
use Time::Piece;
use POSIX qw(strftime);
$a1 = '01.01.1963';
($year, $month, $day) = Decode_Date_US($a1);
print "$year $month $day\n";
$formatted = strftime('%m/%d/%Y',$month,$day,$year);
print "$formatted\n";
I am trying to format dates in a consistent format using POSIX(strftime). I am uncertain what the input format might be. I am using Decode_Date_US to extract the relevant year, month, day information. I am then trying to format the dates in consistent manner using strftime. I am getting following error
Usage: POSIX::strftime(fmt, sec, min, hour, mday, mon, year, wday = -1, yday = -1, isdst = -1) at test_dates.pl line 60
Any help would appreciated.
"use Time::Piece" would be eventually used to sort the dates.
Thanks
Just use Time::Piece and strptime
#!/usr/bin/env perl
use strict;
use warnings;
use Time::Piece;
my $date = '01.01.1963';
my $timestamp = Time::Piece->strptime( $date, "%m.%d.%Y" );
print $timestamp -> strftime( "%m/%d/%Y")
But if the format is inconsistent, then you're onto a loser - for starters, there's plenty of places that transpose day/month ordering, or represent year as two digits (that sometimes will clash with month or day).
It's inherently ambiguous. You can - at best - apply some very crude guessing by grabbing groups of digits and assuming that they're in a consistent order.
E.g.
my ( $day, $month, $year ) = m/(\d{2}).*(\d{2}).*(\d{4})/;
$timestamp = Time::Piece -> strptime ( "$year-$month-$day", "%Y-%m-%d" );
But you'll be tripped up by dates like 10/11/12 because you simply can't know which number is which field. You can try guessing, by evaling the strptime and just retrying different formats until you get one that does decode to something valid.
As you indicate - Decode_Date_US basically does this so:
use strict;
use warnings;
use Date::Calc qw(:all);
use Time::Piece;
my $a1 = '01.01.1963';
my ($year, $month, $day) = Decode_Date_US($a1);
my $time = Time::Piece -> strptime("$year/$month/$day", "%Y/%m/%d");
print $time->strftime("%Y-%m-%d"),"\n";
Also - use strict; use warnings; is good.
And - there's one correct way to write dates. If you're going to reformat at all, then the one that isn't ambiguous is the best choice.
I ended up using DateTime module's strftime function which can handle dates earlier than 1970.
"Crashing" -Perl command line interpreter has stopped working. If it helps, I am using a windows machine and a very infrequent perl user.
this worked for me
use Date::Calc qw(:all);
use DateTime;
$dateformat = "%m/%d/%Y";
($year, $month, $day) = Decode_Date_US($date);
$date = DateTime->new(
year=>$year,
month=>$month,
day=>$day,
);
$date = $date->strftime($dateformat);
I have an ISO 8601 time stored in a variable and I have some number of hours stored in another variable like this:
my $current_time = shift; #looks like: 2015-07-01T15:38:08Z
my $hours = shift; # looks like: 12
My goal is to add the hours to the current time, but there doesn't seem to be any built in Perl function to do it. In Powershell, you can do something like this:
$currentTime = $currentTime .AddHours($hours)
Is there an easy way to do this in Perl?
That specific ISO 8601 profile is also known as RFC3339.
use DateTime::Format::RFC3339;
my $dt = DateTime::Format::RFC3339->parse_datetime('2015-07-01T15:38:08Z');
$dt->add( hours => 1 );
print "$dt\n"; # 2015-07-01T16:38:08Z
If you want to accept arbitrary ISO 8601 profiles, you can use DateTime::Format::ISO8601.
use DateTime::Format::ISO8601;
my $dt = DateTime::Format::ISO8601->parse_datetime('2015-07-01T15:38:08Z');
$dt->set_time_zone('UTC'); # Convert to UTC ("Z") if it's not already.
$dt->add( hours => 1 );
print $dt->iso8601().'Z', "\n"; # 2015-07-01T16:38:08Z
I posted these alternatives because these modules are far less error-prone to use than Time::Piece.
You can also use Time::Moment. In the interest of full disclosure, I am the author of Time::Moment.
say Time::Moment->from_string('2015-07-01T15:38:08Z')
->plus_hours(1);
Output:
2015-07-01T16:38:08Z
Rather easy with Time::Piece:
#! /usr/bin/perl
use warnings;
use strict;
use Time::Piece;
use Time::Seconds;
my $current_time = '2015-07-01T15:38:08Z';
my $hours = 12;
my $format = '%Y-%m-%dT%H:%M:%SZ';
my $time = 'Time::Piece'->strptime($current_time, $format);
$time += $hours * ONE_HOUR;
print $time->strftime($format), "\n";
I'm working on a Perl program at work and stuck on (what I think is) a trivial problem. I simply need to build a string in the format '06/13/2012' (always 10 characters, so 0's for numbers less than 10).
Here's what I have so far:
use Time::localtime;
$tm=localtime;
my ($day,$month,$year)=($tm->mday,$tm->month,$tm->year);
You can do it fast, only using one POSIX function. If you have bunch of tasks with dates, see the module DateTime.
use POSIX qw(strftime);
my $date = strftime "%m/%d/%Y", localtime;
print $date;
You can use Time::Piece, which shouldn't need installing as it is a core module and has been distributed with Perl 5 since version 10.
use Time::Piece;
my $date = localtime->strftime('%m/%d/%Y');
print $date;
output
06/13/2012
Update
You may prefer to use the dmy method, which takes a single parameter which is the separator to be used between the fields of the result, and avoids having to specify a full date/time format
my $date = localtime->dmy('/');
This produces an identical result to that of my original solution
use DateTime qw();
DateTime->now->strftime('%m/%d/%Y')
expression returns 06/13/2012
If you like doing things the hard way:
my (undef,undef,undef,$mday,$mon,$year) = localtime;
$year = $year+1900;
$mon += 1;
if (length($mon) == 1) {$mon = "0$mon";}
if (length($mday) == 1) {$mday = "0$mday";}
my $today = "$mon/$mday/$year";
use Time::Piece;
...
my $t = localtime;
print $t->mdy("/");# 02/29/2000
Perl Code for Unix systems:
# Capture date from shell
my $current_date = `date +"%m/%d/%Y"`;
# Remove newline character
$current_date = substr($current_date,0,-1);
print $current_date, "\n";
Formating numbers with leading zero is done easily with "sprintf", a built-in function in perl (documentation with: perldoc perlfunc)
use strict;
use warnings;
use Date::Calc qw();
my ($y, $m, $d) = Date::Calc::Today();
my $ddmmyyyy = sprintf '%02d.%02d.%d', $d, $m, $y;
print $ddmmyyyy . "\n";
This gives you:
14.05.2014
Frankly I don't know Perl at all. I have to solve a problem using perl for some reasons. I tried searching for quick solutions and couldn't find any (my bad)
Problem: I have got a file that has list of file names and a timestamps (i.e. 2012-05-24T18:19:35.000Z) in it.
I need to parse identify which of these are more that 90 days old.
I just need the check, everything else I think I have got in place already. When I googled some people suggested using some fancy datetime packages while some suggestions were around using of -M.
Quite confused actually. All help appreciated. Thanks.
This format is defined by both RFC3339 (rather specifically) and ISO8601 (among many others).
use strict;
use warnings;
use feature qw( say );
use DateTime qw( );
use DateTime::Format::RFC3339 qw( );
my $limit_dt = DateTime->now->subtract( days => 90 );
my $format = DateTime::Format::RFC3339->new();
while (<>) {
chomp;
my ($timestamp, $filename) = split(' ', $_, 2);
my $dt = $format->parse_datetime($timestamp);
say($filename) if $dt < $limit_dt;
}
For example,
$ cat data
2012-05-24T18:19:35.000Z new
2012-02-25T18:19:35.000Z old
2012-02-24T18:19:35.000Z ancient
$ perl script.pl data
ancient
To ignore the time portion and just check if the date part is more than 90 days ago, use the following instead:
my $limit_dt = DateTime->today( time_zone => 'local' )->subtract( days => 90 );
That date format has the advantage that doing a lexicographical comparison between two of those string is (just about) the same as doing a date-time comparison. So you just need to get the date 90 days in the past into that format, and doing a string comparison.
use POSIX 'strftime';
$_90_days_ago = strftime("%FT%T.000Z", gmtime( time-90*86400 ));
...
foreach $date (#your_list_of_dates) {
if ($date lt $_90_days_ago) {
print "$date was at least 90 days ago.\n";
} else {
print "$date is less than 90 days ago.\n";
}
}
Something like this should work:
#! perl -w
use strict;
use Time::Local;
# 90 times 24 hours of 60 minutes, 60 seconds
my $ninety_days = 24 * 60 * 60 * 90;
my $now = time;
# parse the time stamps in the file
while (<INPUTFILE>)
{
chomp();
if (/(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})/)
{
my $year = $1;
my $month = $2;
my $day = $3;
my $hour = $4;
my $minute = $5;
my $second = $6;
# Looks like these are in GMT ("Z") so we'll use timegm
my $time = timegm($second,$minute,$hour,$day,$month - 1,$year - 1900);
if (($now - $time) > $ninety_days)
{
print "$_ is more than 90 days ago!
}
}
}
(that's just the basic - it needs the details about opening the data file, etc)
You should take a look to this Perl module https://metacpan.org/pod/Date::Manip