Perl Format dates - perl

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

Related

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

Add time to ISO 8601 times in Perl

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

How to display 4/25/10 to 2010-25-04?

my$str= '4/25/10';
my$sr = join(' ',split (/\//,$str));
#my$s = sprintf '%3$d %2$d %1$d',$srt;
print$sr,"\n";
output:
4 25 10
But i want output like 2010-25-04.Can any one suggest me how display the my desire output.Give me your suggestion
you answers will be appreciable.
Well, a braindead solution might be:
my #date = split( /\//,$str)
printf("%04d-%02d-%02d", $date[2] + 2000, $date[1], $date[0]);
You could write something a little more self-documenting by highlighting what you expect to be year, month and day like so:
my ($day, $month, $year) = split /\//, $str;
printf("%04d-%02d-%02d", $year + 2000, $month, $day);
You're not that far off.
Instead of splitting and joining in a single operation, you can keep individual variables to handle the data better:
my ($d,$m,$y) = split /\//, $str;
Then you can format it in most any way you please, for example:
printf "20%02d-%02d-%02d\n", $y, $d, $m;
A few notes, though:
I won't comment about the source format, but the format you're converting to doesn't make a lot of sense. You'd probably be better using ISO-8601: 2010-04-25.
Obviously, this way of doing only works up to year 2099.
For anything more serious, you'd be better off delegating this kind of work to date handling modules. See for example this question for parsing and this question for formatting
use DateTime::Format::Strptime;
my $strp = DateTime::Format::Strptime->new(
pattern => '%m/%d/%y',
locale => 'en_US'
);
my $dt = $strp->parse_datetime('4/25/10');
print $dt->strftime('%Y-%d-%m'), "\n";
Gives:
2010-25-04
No need to do to DateTime for this. Time::Piece has been included with the Perl core distribution for years.
#!/usr/bin/perl
use strict;
use warnings;
use 5.010;
use Time::Piece;
my $date = '4/25/10';
my $date_tp = Time::Piece->strptime($date, '%m/%d/%y');
say $date_tp->strftime('%Y-%m-%d');

convert date format from 9/15/12 to 255 in perl

I was wondering if someone could show me how to convert 9/15/12 to 255 format.
Something in php from getdate array you can get ydate.
I think you're asking how you can get the 1 <= yday <= 366 day representation of a date, similar to yday in php's getdate(). As is common in PERL, there's more than one way to do it. The simplest mechanism would be to use localtime() for today's date:
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
If you want to do it for a different date, I'd probably use the TimeDate CPAN module
use Date::Parse;
print time2str("%j",str2time("9/15/2012"));
I think Tawnos's mentioning php's yday from getdate() is on target. Here's one option (assuming 2012 is the year in your date string):
use strict;
use warnings;
use Date::Calc qw/Day_of_Year/;
my $date = '9/15/12';
my ( $month, $day, $year ) = split '/', $date;
my $doy = Day_of_Year( "20$year", $month, $day ) - 1;
print $doy; # (0 - 365)
Output:
258
Do you want the day of the year? That would be day 258 (0-based) or the 259th day (1-based), though. Using only core Perl:
use Time::Local qw( timegm );
my $date = '9/15/12';
my ($m,$d,$y) = split(qr{/}, $date);
my $epoch = timegm(0,0,0, $d,$m-1,$y);
my $yday = ( gmtime($epoch) )[7]; # 258 (0-based index)
Note that timegm+gmtime is applicable no matter the time zone of the date.
Here's another way, using the core module Time::Piece :
#!/usr/bin/env perl
use strict;
use warnings;
use Time::Piece;
my $t = Time::Piece->strptime(shift,"%m/%d/%y");
print $t->yday, "\n";
The day output is zero-relative: January 01 = 0.
my $dt = '9/15/2012';
my ( $m, $d, $y ) = split( '/', $dt );
my $t = POSIX::mktime( 0, 0, 0, $d, $m - 1, $y - 1900 );
say [ localtime $t ]->[7] - 3;
Julian date (minus 1) is slot 7 in the list return from localtime and gmtime.
Why subtract 3? I don't know; Sept 15 is 259 Julian. Still it performs the function mapping '9/15/2012' to 255.
You can use only function strftime from core module POSIX.
use strict;
use POSIX qw(strftime);
print strftime "%j", localtime(time);

Today's Date in Perl in MM/DD/YYYY format

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