Getting a Day from Date in Perl - perl

Is there a way to find out day of the week when provided a date. How would I code this in Perl?
For example
Given 02-02-2016(dd-mm-yyyy) outputs Friday
Note: Without using any modules.

Note: Without using any modules.
Calendaring is hard. No, calendaring is REALLY HARD! It's very easy to get wrong. Use a module.
Fortunately there's a built in module to do this, Time::Piece. It has strptime to parse the date into an object. From there you can ask it a great number of things.
use v5.10;
use strict;
use warnings;
use Time::Piece;
my $time = Time::Piece->strptime("02-02-2016", "%d-%m-%Y");
say $time->fullday;

Related

How to calculate difference between 2 time stamps in PERL

Code to calculate the difference between 2 given time stamps. Start_Time="2017-09-19 19:36:12.763" End_Time="2017-09-19 19:36:22.72" I want to get the difference between above 2 time stamps also considering the milliseconds.
This is what i tried:
#!/usr/bin/perl
use strict;
use warnings;
use Date::Parse;
use Date::Format;
$startdat = "2007-11-17 12:51:22";
$stopdate = "2007-11-17 12:52:22";
my ($years, $months, $days, $hours, $mins, $secs) = split /\W+/, $startdat;
my ($yeart, $montht, $dayt, $hourt, $mint, $sect) = split /\W+/, $stopdate;
my $times = timelocal($secs,$mins,$hours,$days,$months,$years);
my $timet = timelocal($sect,$mint,$hourt,$dayt,$montht,$yeart);
$time = $timet - $times;
print $time;
But this gives me an error: Can't locate Date/Parse.pm in #INC.
You are getting that error message because Date::Parse isn't installed. This module isn't a part of the standard Perl distribution and needs to be installed separately. If you want to use it, then you need to install it.
However.
Although you use Date::Parse and Date::Format in your code, you don't actually make use of them. So you can just delete those two lines. Then your code will probably work.
Date::Parse and Date::Format are actually quite dated modules. For date and time work in Perl, I recommend Time::Piece (which is a standard part of the Perl library) or DateTime (which needs to be installed).

Get ISO DateTime with only core modules in Perl?

I would like to get a date-time string such as 2015-06-17 10:20:34 with only core modules. The reason of this is that cpan install DateTime takes ages on my machine because of the tests and the fetch of all the dependencies.
If I give my Program to my colleagues. They will also need to install the missing modules. However, if I simply do:
my $date = `date "+%Y-%m-%d %H:%M:%S"`; chomp $date;
It takes only one line, it requires no additional modules and works on all POSIX machines.
Why should I need to install DateTime in this case?
Yet DateTime->now is the solution recommended by google. I think it shouldn't, I think I am wrong and I can't figure out why.
Perl 5.14 contains the core module Time::Piece, which has a datetime method that returns a date and time in ISO 8601.
use Time::Piece;
my $t = localtime;
say $t->datetime;
This will return 2015-06-17T10:59:15. If you don't want the T, remove it.
say localtime->datetime =~ y/T/ /r;
The Time::Piece module has been in core Perl since version 5.10, about eight years ago
It overrides the localtime core function and looks like this
use Time::Piece;
print localtime->datetime;
output
2015-06-17T12:55:36
If you really want a space instead of the standard T then, on Perl v5.14 or later you can write
print localtime->datetime =~ tr/T/ /r;
In earler versions, which don't have the /r "non-destructive" option, you would have to put the string into a variable and modify it with tr/T/ /
This is simple with the POSIX function strftime:
use POSIX qw( strftime );
print strftime "%Y-%m-%d %H:%M:%S", localtime;
POSIX has been core since 5.0.
Time::Piece gives you an object with many useful methods. As other people have pointed out, the datetime() gives you the date and time in ISO format.
use Time::Piece;
print localtime->datetime;
But if you want a different format (like the "not quite ISO" format in your question) you can use the strftime() method.
use Time::Piece;
print localtime->strftime('%Y-%m-%d %H:%M:%S');
A couple of other points:
Your DateTime installation might go quicker if you used a pre-built package (for example, yum install perl-DateTime on a RedHat derived system).
There are two reasons for avoiding shelling out to run system commands - firstly you lose cross-platform compatibility and secondly creating a new shell is a relatively slow and expensive operation.

Perl - store output of localtime into hash

In perl I am able to get current seconds using this sequence of commands:
my #time = ($sec,$min,$hour,$day,$mon,$year_1900,$wday,$yday,$isdst)=localtime;
print $time[0]
Is there any equivalent of this but using hashes? So one can type something like this:
print $time{"sec"}
I have tried:
my %time= ("sec","min","hour","day","mon","year_1900","wday","yday","isdst")=localtime;
print $time{"sec"}
But it ended with following error:
Can't modify constant item in list assignment at -e line 1, near "localtime;"
Execution of -e aborted due to compilation errors.
Thanks
Instead of storing everything in a hash, you can store it in an object using Time::Piece:
#!/usr/bin/perl
use strict;
use warnings;
use Time::Piece;
my $t = localtime;
print $t->sec;
Time::Piece can do date math, comparisons, parsing, and output, making it more flexible than a simple hash.
You can use hash slice
my %time;
#time{"sec","min","hour","day","mon","year_1900","wday","yday","isdst"} = localtime;
# or shorter
# #time{qw(sec min hour day mon year_1900 wday yday isdst)} = localtime;
print $time{"sec"};
There are a few standard Perl modules that can help you.
The first is Time::localtime. Thie replaces the internal localtime command with a by name methods for accessing the various parts of the time:
use strict; # Always
use warnings; # Always
use feature qw(say); # An improved version of the print command
use Time::localtime
my $time = localtime; # A Time::Tm object, not your standard localtime command
say $time->sec; # Prints the seconds
This isn't quite the hash you've requested, but you can see that it greatly improves the access to the various pieces provided by localtime in a way that's almost like a hash.
You can also see the use of say which is like print except that you don't need that pesky \n on the end (like you forgot in your example).
Taking things to the next step...
Another nice standard module is called Time::Piece. It provides even easier ways to parse time and to display it.
use strict; # Always
use warnings; # Always
use feature qw(say); # An improved version of the print command
use Time::Piece
my $time = localtime;
say $time->sec; # Prints the seconds. Looks pretty much the same
#
# But now look!
#
say $time->ymd; # Prints the time as YYYY-MM-DD
say $time->ymd("/"); # Prints the time as YYYY/MM/DD
say $time->mdy("/"); # Prints the time as MM/DD/YYYY
say $time->month; # Prints the name of the month
say $time->cdate; # Prints date and time as a string
I prefer Time::Piece because of its flexibility and the ease of initializing a date that's not the current time. If you have a string for the date/time, and you can describe it, you can easily create a new Time::Piece date/time object that can be manipulated.
One of the many things Perl programmers miss is the cornucopia of standard Perl modules that are packed into almost every Perl distribution. These modules do not require downloading or installation. They're there and available on almost any computer that has that particular Perl release.
You can use File::Copy for that missing file copy command. You can use File::Basename for that missing basename and dirname command. You can use the hundreds of modules that come with Perl to make your life easier. Take a tour of the standard Perl documentation and play around with it.

Perl date format transformations

I'm taking 02/29/2012 from an html form, but will need to work with the ISO 2012-02-29 from then on.
I am certain that it'd be easier for me to do it with Perl without touching on the JS datepicker of which I have zero understanding.
$date = '02/29/2012';
$date =~ s#(\d+)/(\d+)/(\d+)#$3-$1-$2#;
To do your transformation, just use
s{([0-9]{2})/([0-9]{2})/([0-9]{4})}{$3-$2-$1}
But AFAIK, ISO is not YYYY-DD-MM, but YYYY-MM-DD.
You could use DateTime or Date::Manip. There are a plenty of subroutines that perform various manipulations with date. For example, using Date::Manip:
$string = '02/29/2012';
$date = ParseDate($string);
$out = UnixDate($date, '%Y-%m-%d');
Edit: as I see, a similar answer was provided while I was typing
You can use the Date::Manip::Date module.
This is a little costlier but does validation of the dates.
Using standard Perl:
#!/usr/bin/perl
use strict;
use warnings;
use 5.010;
my $date = '02/09/2012';
say join '-', (split m|/|, $date)[2,1,0];
Using DateTime:
#!/usr/bin/perl
use strict;
use warnings;
use 5.010;
use DateTime::Format::Strptime;
my $date = '02/09/2012';
my $parser = DateTime::Format::Strptime->new(
pattern => '%d/%m/%Y',
);
my $dt = $parser->parse_datetime($date);
say $dt->ymd;
If you want to deal with dates and times in Perl, then DateTime and its friends are the tools that you want.
It depends on how much work you're going to be doing on the dates, and whether you're going to be culturally aware of how different people enter dates, and whether you're going to accept month names or abbreviations as well as pure numerics, and ...
On CPAN, there's a major section on Data and Data Types which has sub-sections for Date and Time with many modules in each. Some are extremely elaborate: for example, the DateTime module is extremely thorough, but rather heavy-weight (and is listed in neither the Date nor the Time section). Others are just clever: Date::Calc and Date::Manip. The main problem at CPAN is the embarrassment of riches - what you need is probably there.
If the simple regexes in other answers will work, use them. Otherwise, consider one of Date::Calc or Date::Manip, unless you find something else that will work better for you.
The strptime function can also be leveraged from the core module, Time::Piece :
use Time::Piece;
my $date = q(02/29/2012);
my $t = Time::Piece->strptime( $date, "%m/%d/%Y" );
print $t->ymd, "\n";
As the input is not trusted (web form...) I suggest to basically use choroba's answer (with bounds checking added), but in a test that checks if the input matches:
# input and result are in $_
unless (s{^([0-9]{2})/([0-9]{2})/([0-9]{4})$}{$3-$2-$1}) {
die "invalid input";
}
# From here input is both validated and transformed

Undefined subroutine &main::timelocal error

I have the following error when I execute my perl module :
Undefined subroutine &main::timelocal
I have defined time and I want in the format of DDMMYYYY without any seperators.
Can anyone help me on this?
To use timelocal like that, you need to import it:
use Time::Local 'timelocal';
(and make sure you are calling it correctly; see Time::Local)
But perhaps you meant localtime? Or you might want POSIX::strftime.
You was not very specific where to get the time. This works for current date, using core Time::Piece module:
use Time::Piece;
print localtime->dmy(''); # 05042011
If you have time in variable, you can do
use Time::Piece;
print localtime($time)->dmy('');
The empty string in dmy call is separator.
The core POSIX module contains a 'strftime' function that handles all of the standard Unix date/time formatting sequences.
$ perl -MPOSIX=strftime -le'print strftime "%d%m%Y", localtime'
Or, in a program,
use POSIX 'strftime';
print strftime '%d%m%Y', localtime, "\n";
It's an old one but I had this exact error and solved it from looking at the above examples with a different solution.
Reason was that I had not included the ';' at the end of the use statement!
use Time::Local ;