How to compare dates using perl? - perl

How can i compare two dates in the format using Perl:
"dd mon yyyy hh:mm:ss GMT"
e.g.: 12 May 2013 10:10:20 GMT
I cannot install any external Perl modules.
Please advice.

If you have Perl v5.9.5 or newer, you can use Time::Piece core module. Here's a simple demonstration of relevant operations
Convert the dates from string to Time::Piece object
my $date = "12 May 2013 10:10:20 GMT";
my $tp1 = Time::Piece->strptime($date, "%d %B %Y %T %Z");
my $tp2 = ...
Find the difference between the 2 time
my $diff = $tp2 - $tp1;
which gives you a Time::Seconds object.
Finally, display the difference in units of seconds (or something else).
print $diff->seconds;
Or you could just compare the two directly (thanks stevenl)
$tp2 > $tp1
References:
Time::Seconds
Time::Piece
man strftime for format string to use with Time::Piece->strptime
man strptime for format string to use with $tp->strftime
Note that only format characters aAbBcdHIjmMpSUwWxXyYZ% are safe if you're using non-Unix system (for example, Window's Perl doesn't support the %e specifier).

Convert the dates to the format yyyymmddhhmmss (e.g. 20130512101020) and compare as strings. Handling the time zones might get tricky without modules, though.

One of the most popular date modules is DateTime. It has a FAQ which may help you get started.
sub to_comparable {
my ($date) = #_;
my ($H,$M,$S,$d,$m,$Y) = $date =~ m{^([0-9]{2}):([0-9]{2}):([0-9]{2}), ([0-9]{2})/([0-9]{2})/([0-9]{4})\z}
or die;
return "$Y$m$d$H$M$S";
}
if (to_comparable($date2) < to_comparable($date1)) {
...
} else {
...
}

Related

Converting string to date time using Perl

I am not a perl programmer, but I'm trying to update someone else's code. I need to format the date and time. I have three variables returned from a database. One variable contains the time, one has AM/PM, on has the date in mm/dd/yyyy format. For example:
variable1 = 10:00
variable2 = PM
variable3 = 11/27/2019
I need to take these three variables and format them accordingly: 2019-11-27 20:00:00
How could I go about doing this?
The strptime and strftime functions can do this. One version of these is provided by the core module Time::Piece:
use strict;
use warnings;
use Time::Piece;
my $time = '10:00';
my $ampm = 'PM';
my $date = '11/27/2019';
my $tp = Time::Piece->strptime("$date $time $ampm", '%m/%d/%Y %I:%M %p');
print $tp->strftime('%Y-%m-%d %H:%M:%S'), "\n";

Compare date time zone with time() in perl

I am trying to compare a file creation time which is in the format: 08-07-2016 08:16:26 GMT with the current time using time() in perl.
Since time() returns epoch time, I am not sure how to find the time difference between these two different time formats.
I tried something like below and for obvious reasons, I get an error saying: "Argument 08-07-2016 08:16:26 GMT" isn't numeric in subtraction".
my $current_time = time();
my $time_diff = $creation_time - $current_time;
if ($time_diff > 10) { #compare if the difference is greater than 10hours
# do something...
}
Some of the questions I have:
Since I want to compare only the hour difference, how can I extract just the hours from both these time formats?
I am unsure if the comparison of $time_diff > 10 is right. How to represent 10hours? 10*60?
OR is there a way to at least convert any given time format into epoch using DateTime or Time::Local?
How can I pass a a date parameter to a DateTime constructor?
my $dt1 = DateTime-> new (
year =>'1998',
month =>'4',
day =>'4',
hour =>'21',
time_zone =>'local'
);
Instead can we do something like
my $date = '08-07-2016 08:16:26 GMT';
my $dt1 = DateTime->new($date); # how can i pass a parameter to the constructor
print Dumper($dt1->epoch);
Thanks in advance for any help.
Time::Piece has been a standard part of Perl since 2007.
#!/usr/bin/perl
use strict;
use warnings;
use 5.010;
use Time::Piece;
use Time::Seconds;
my $creation_string = '08-07-2016 08:16:26 GMT';
my $creation_time = Time::Piece->strptime($creation_string, '%d-%m-%Y %H:%M:%S %Z');
my $current_time = gmtime;
my $diff = $current_time - $creation_time;
say $diff; # Difference in seconds
say $diff->pretty;

Perl convert localtime to unix (epoch) time

using perl, I am trying to estimate the time since a file was created.
I would like to convert the local time to unix time (epoch), then take unix time of the file & subtract.
The problem I face is that when I convert localtime to unixtime , it is converted incorrectly!
my $current = str2time (localtime(time));
print $current;
The results I get are
2768504400 = Sun, 23 Sep 2057 21:00:00 GMT
2421349200 = Sun, 23 Sep 2046 21:00:00 GMT
Do I have to feed str2time with a specific date format?
You're doing something bizarre here - localtime(time) takes - the epoch time (time) and converts it to a string.
And then you convert it back.
Just use time()
Or perhaps better yet -M which tells you how long ago a file was modified. (In days, so you'll have to multiply up).
e.g.:
my $filename = "sample.csv";
my $modification = -M $filename;
print $modification * 84600;
But if you really want to take the time and convert it back again - you'll need to look at how localtime(time) returns the result.
If you do:
print localtime(time);
You get:
5671624811542661
Because localtime is being evaluated in a list context, and so returning an array of values. (Which you can use without needing to parse).
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) =
localtime(time);
If you do it in a scalar context, it returns a string denoting the time:
print "".localtime(time);
Gives:
Thu Sep 24 16:09:33 2015
But note - that might vary somewhat depending on your current locale. That's probably why str2time is doing odd things - because it makes certain assumptions about formats that don't always apply. The big gotcha is this:
When both the month and the date are specified in the date as numbers they are always parsed assuming that the month number comes before the date. This is the usual format used in American dates.
You would probably be better off instead using Time::Piece and strftime to get a fixed format:
e.g.
use Time::Piece;
print localtime(time) -> strftime ( "%Y-%m-%d %H:%M:%S" );
Note - Time::Piece overloads localtime so you can actually use it (fairly) transparently. Of course, then you can also do:
print localtime(time) -> epoch;
And do without all the fuss of converting back and forth.
You have missed requesting localtime to produce scalar (string) instead of array.
use Date::Parse;
my $current = str2time (scalar(localtime(time)));
print $current, "\n";
print scalar(localtime($current)),"\n";
perldoc -f localtime
Converts a time as returned by the time function to a 9-element
list with the time analyzed for the local time zone. Typically
used as follows:
# 0 1 2 3 4 5 6 7 8
($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
...
In scalar context, "localtime()" returns the ctime(3) value:
$now_string = localtime; # e.g., "Thu Oct 13 04:54:34 1994"

Is there a perl 5.005 core module that would convert epoch seconds to a datetime string?

Is there a perl core module in 5.005 that would convert epoch seconds to printable datetime?
Our system has DateTime.pm, but the script in need of the functionality is still on Perl 5.005 and not feasible to upgrade it to 5.6+ (don't ask. Just Cant Be Done for non-technical reasons). DateTime.pm - at least the version we have - requires 5.6.
Therefore I need one of the following:
Ideally, a module that is in Perl 5.005 core that would convert epoch seconds to date/time string. Preferably in YY/MM/DD hh:mm:ss format but not required.
Failing that, a 5.005-compatible non-XS module that would convert epoch seconds to date/time string. Preferably in YY/MM/DD hh:mm:ss format but not required.
Strong preference for a module that would have had this functionality on CPAN when Perl 5.005 was released (that way it is plausible it'd be in company's existing set of CPAN modules)
According to CPAN the POSIX module is available. So you can use the strftime function. This is what I use all the time in 5.8.8
use POSIX();
my $time_t = 1234567890;
my $txt = POSIX::strftime( "%Y-%m-%d %T", localtime($time_t) );
print "$txt\n";
Gives
2009-02-14 10:31:30
See the core routines localtime and gmtime (also time).
IMHO, it's usually easier to write a small subroutine to do this sort of formatting than to introduce a new dependency. For example:
sub epoch_to_datetime {
my $time = shift(#_) || time();
my ($s, $m, $h, $md, $mo, $yr) = localtime($time);
my $date = join("/",
sprintf("%02d", $yr % 100),
sprintf("%02d", $mo + 1),
sprintf("%02d", $md));
my $time = join(":",
sprintf("%02d", $h),
sprintf("%02d", $m),
sprintf("%02d", $s));
return "$date $time";
}
print epoch_to_datetime(time()) . "\n";
# 11/11/09 08:06:10
The POSIX::strftime solution is the most flexible one. But if you're not very choosy about the exact format, then you can use localtime (or gmtime) in scalar context to get a human-readable datetime string from epoch seconds.
$ perl -le'print scalar localtime 1000000000'
Sun Sep 9 02:46:40 2001

How to parse a string into a DateTime object in Perl?

I know about the DateTime Perl module, and many of the DateTime::Format:: modules to parse specific kinds of date/time formats. However given some examples of date/time strings, how can I figure out (at coding/design time, not at runtime) which specific module should I use?
For example, I want to parse strings like: October 28, 2011 9:00 PM PDT
Is there a list somewhere of the most common date/time formats where I could look this up and find which would be the most suitable module?
I also know about some modules which try to "guess" the format for each given string at runtime and do their best. But, for sensitive applications, I would like to determine (as strictly as possible) the format first when designing an application, and then use a module which will warn me if a string does not match the specified format.
How should I go about this?
DateTime::Format::Strptime takes date/time strings and parses them into DateTime objects.
#!/usr/bin/perl
use strict;
use warnings;
use DateTime::Format::Strptime;
my $parser = DateTime::Format::Strptime->new(
pattern => '%B %d, %Y %I:%M %p %Z',
on_error => 'croak',
);
my $dt = $parser->parse_datetime('October 28, 2011 9:00 PM PDT');
print "$dt\n";
The character sequences used in the pattern are POSIX standard. See 'man strftime' for details.
I tend to use Time::Piece simply because it's part of the standard Perl module set since version 5.10.
You can't beat it's ability to parse date strings.
my $time = Time::Piece->strptime(
"October 28, 2011 9:00 PM PDT",
"%B %d, %Y %r %Z");
Have a look at the Date::Parse module, i.e. the str2time() function. It has support for most of the commonly used formats.
Example:
use Date::Parse;
use DateTime;
my $str = "Tue, 20 Sep 2011 08:51:08 -0500";
my $epoch = str2time($str);
my $datetime = DateTime->from_epoch(epoch => $epoch);
If you are looking for common date/time formats
have a look at DateTime::Locale
use DateTime::Locale
my $locale = DateTime::Locale->load('DE_de');
The following methods return strings appropriate for the DateTime->format_cldr() method:
$locale->date_format_full()
$locale->date_format_long()
$locale->date_format_medium()
$locale->date_format_short()
$locale->date_format_default()
$locale->time_format_full()
$locale->time_format_long()
$locale->time_format_medium()
$locale->time_format_short()
$locale->time_format_default()
$locale->datetime_format_full()
$locale->datetime_format_long()
$locale->datetime_format_medium()
$locale->datetime_format_short()
$locale->datetime_format_default()
You can parse Dates with the DateTime::Format::CLDR module
use DateTime::Format::CLDR;
# 1. Basic example
my $cldr = DateTime::Format::CLDR->new(
pattern => 'dd.MM.yyyy HH:mm:ss',
locale => 'de_DE',
time_zone => 'Europe/Berlin',
);
my $dt = $cldr->parse_datetime('26.06.2013 11:05:28');
DateTime::Format::Natural is also a good candidate.
Test:
perl -MDateTime::Format::Natural \
-E "my $d=DateTime::Format::Natural->new->parse_datetime('October 11, 2021'); say $d->month;"
10