%-d flag with specifier not working - perl

My platform is Linux. I want the printed date to be formatted as Apr 3, 2014, 5:28 PM when given input such as 2014-04-03T17:28:54.864Z.
My current Perl script.
#!/usr/bin/perl
use lib '/tmp/DateTime/Format';
use DateTime::Format::ISO8601;
my $date = "2014-04-03T17:28:54.864Z";
my $iso8601 = DateTime::Format::ISO8601 -> new;
my $dt = $iso8601->parse_datetime( $date );
print "Date before conversion *******-> \"$date\"\n";
my $s6 = $dt->strftime("%b %-d, %Y, %I:%M %p");
print "Date after conversion *******-> \"$s6\"\n";
It gives the output Apr %-d, 2014, 05:28 PM. When the day of the month or hour is a single digit, I do not want zero or space padding. I want the output as Apr 3, 2014, 5:28 PM when day and hour are each a single digit.

I see no %-d option listed in the valid strftime patterns.
You could use %e to get a leading space instead of a leading zero but, since you discount that, you can get the day independently, then change it and use that changed value within the format string, something like (untested, but you'll get the idea):
# Get day and remove leading zero.
my $dayofmonth = $dt->strftime("%d");
$dayofmonth =~ s/^0//;
# Construct format string from "hard-coded" day.
my $s6 = $dt->strftime("%b " . $dayofmonth . ", %Y, %I:%M %p");

Try this:
my $s6 = $dt->format_cldr('MMM d, Y, h:mm a');
It makes use of the module:
DateTime::Format::CLDR - Parse and format CLDR time patterns
Which you can find documented here.

Because there aren't any strftime patterns for days other than %d and %e, the easy solution is just to edit the result after the fact
$s6 =~ s/\s+/ /g;
This would change your script to the following:
use strict;
use warnings;
use DateTime::Format::ISO8601;
my $date = "2014-04-03T17:28:54.864Z";
my $iso8601 = DateTime::Format::ISO8601->new;
my $dt = $iso8601->parse_datetime( $date );
print qq{Date before conversion *******-> "$date"\n};
my $s6 = $dt->strftime("%b %e, %Y, %I:%M %p");
$s6 =~ s/\s+/ /g;
print qq{Date after conversion *******-> "$s6"\n};

Related

How to format date to "2018-10-29 11:49:33"

I have to convert the GMT date to region specific date with format like "YYYY-MM-DD H:M:S".
Code developed is :-
use Time::Local;
($year,$mon,$day) = split /\-/, $ARGV[0];
($hrs,$min,$sec ) = split /:/, $ARGV[1];
$time = timegm( $sec, $min, $hrs, $day, $mon-1, $year-1900);
print scalar localtime($time), "\n";
But when I run it like :-
$ perl testDateGMTToLocal.pl 2018-10-29 11:49:33
It gives o/p converted in local time zone:-
Mon Oct 29 07:49:33 2018
But I want this o/p in below format
29-OCT-18 07:49:33
Thanks in advance.
I'd recommend to do it all using modules. The all-capable and very complete module is DateTime, and for this job you'd also need DateTime::Format::Strptime.
One other option is the simpler and much smaller core module Time::Piece
use warnings;
use strict;
use feature 'say';
use Time::Piece;
die "Usage $0 YYYY-MM-DD H:M:S" if #ARGV != 2;
my $time = join ' ', #ARGV;
my $tp = Time::Piece->strptime($time, "%Y-%m-%d %T");
my $local = localtime($tp->epoch);
say $local;
# In the desired format
say join('-', $local->mday, uc $local->month, $local->yy),
' ', $local->hms;
# If "Oct" is ok instead of block capitals for month abbreviation
say $local->strftime("%d-%b-%y %T");
This converts GMT time, with invocation as in the question, to the local time on my machine
Mon Oct 29 04:09:33 2018
29-OCT-18 04:09:33
29-Oct-18 04:09:33
where the middle one was asked for.
On some systems there is the %F format specifier for %Y-%m-$d.† There may be a defined format for 29-OCT-18, in which case you don't have to patch it by hand, but I am not aware of it.
† Or the module has its own formatting in which case that's portable. But origin of the error when it fails to do %F on my system isn't clear to me in that sense.
You can use
use POSIX qw( strftime );
print(strftime("%d-%b-%y %H:%M:%S", localtime($time)), "\n");

To subtract two Time:Piece objects

I want to get the difference between time in minutes. Both the timings to be compared are in same timezone so no worries about the time zone difference and all.
Say if Start_time = 14 Apr 2016 05:02:26 (which is collected form log line) and for end time would be the current time of machine,
I want to calculate end time - start time. For that I need the Start time to be in format of current time.
I tried subtracting current time which is already a Time::Piece Object and converting $start_time into Time:Piece object.
But I am getting "Error parsing time at C:/Perl/lib/Time/Piece.pm line 469, line 1071883." error. Please suggest.
Also this "1071883" num in error is changing everytime I run the script. Not sure if its a kind of garbage value or what.
Editing the code with below suggested answer
I am getting below output. Seems the problem is coming as $now contains the DAY value like saturday but our $start_time doesnt. However i cant make any change in start time like adding the day value to it as we are collecting it from a log file. If the problem is due to the reason I stated, Kindly suggest how to ignore that day value from $now.
Output :
last line of log: 16 Apr 2016 03:41:49 -- DEBUG -- 16 Apr 2016 03:41:49
Time is Sat Apr 16 03:43:02 2016
difference is 21673
Below is what I tried:
#get last line of log
open my $fh ,"<","$slogfile";
my $last_line;
$last_line = $_,while (<$fh>);
print OUTLOG "last line of log: $last_line \n";
if ($last_line=~ m/^(\d\d) (\w{3}) (\d{4}) (\d\d):(\d\d):(\d\d) --/) {
$start_time = "$1 $2 $3 $4:$5:$6";
print OUTLOG "$start_time\n";
} else {
print OUTLOG "pattern matching didnt work\n";
}
#get current time
my $t = localtime;
#my $current_time = $t ;
print OUTLOG "Time is $current_time \n";
my $format = '%d %b %Y %H:%M:%S';
my $diff = $t - Time::Piece->strptime($var, $format);
print OUTLOG "difference is $diff \n";
Your format doesn't match the format of your date. The format you're using is "'%a %b %d %H:%M:%S %Y", which would match "Thu Apr 14 05:02:26 2016". You can get an explanation of the various pieces of your format from "man strftime" or "man strptime".
I've corrected the format definition in this example.
#!/usr/bin/perl
use strict;
use warnings;
use 5.010;
use Time::Piece;
my $format = '%d %b %Y %H:%M:%S';
my $start_time = '14 Apr 2016 05:02:26';
my $now = localtime;
my $diff = $now - Time::Piece->strptime($start_time, $format);
say "$diff seconds"; # $diff stringifies to seconds
say $diff->minutes, ' minutes';
The output is:
186402 seconds
3106.7 minutes
Update:
Seems the problem is coming as $now contains the DAY value like
saturday but our $start_time doesnt. However i cant make any change in
start time like adding the day value to it as we are collecting it
from a log file. If the problem is due to the reason I stated, Kindly
suggest how to ignore that day value from $now.
No. That's not the problem at all. If you print out the the Time::Piece object that you parse from $start_time then you'll see that also has the day name included. That's just how Time::Piece objects stringify.
The actual problem is more subtle. It seems that when Time::Piece parses a date string, it assumes that it is in UTC unless the string contains an explicit time zone. From what you're saying I'm assuming that your on the east coast of the US, which would explain the ~6 hour differences that you're getting.
I'm investigating this further and will almost certainly submit a patch to Time::Piece to fix this (it might just be a documentation patch to make the behaviour clearer). But in the meantime, you need a fix. And that's pretty simple. You just need to add the time zone to your code. The relevant sections of your code will now look like this:
my $format = '%d %b %Y %H:%M:%S%z'; # %z added here
# Append timezone here (-0600 as you're six hours behind UTC -
# adjust that if my assumption is wrong)
my $diff = $t - Time::Piece->strptime($var . '-0600', $format);
Or (as, quite rightly, pointed out in the comments by Borodin) you could just switch to using UTC throughout).
my $t = gmtime;
my $format = '%d %b %Y %H:%M:%S';
my $diff = $t - Time::Piece->strptime($var, $format);

Perl Date String Parsing with Time::Piece

For some reason I am having a lot of trouble parsing date strings using Time::Piece.
So this works:
my $t = Time::Piece->strptime( 'Sunday, November 4, 2012 10:25:15 PM -0000' , "%A, %B %d, %Y %I:%M:%S %p %z" );
print $t;
But this does not:
my $temp_time = Time::Piece->strptime('7/23/2014 5:24:22 PM', "%-m/%-d/%Y %l:%M:%S %p");
print $temp_time;
I have also used '%D %r' as the format string but that also does not work. Do any of you have insight as to why this might be? For reference , the hour is 1-12 (not 01-12) and the month is 1-12 (not 0-12).
Thanks!
Change
"%-m/%-d/%Y %l:%M:%S %p"
to
"%m/%d/%Y %l:%M:%S %p"

How do I convert datetime to a different format? [perl]

Need help parsing the datetime stamp and splitting it up by date and time.
use strict;
use warnings;
use Time::Piece;
my $string = "05:57:03 08/31/10 MDT";
print $string,"\n";
my $time = Time::Piece->strptime($string, "%H:%M:%S");
my $date = Time::Piece->strptime($string, "%Y/%m/%d");
print $time,$date,"\n";
Thanks! Also how do I figure out which day of week this is using code?
use DateTime::Format::Strptime;
my $s = DateTime::Format::Strptime->new(pattern => '%T %D %Z');
my $dt = $s->parse_datetime('05:57:03 08/31/10 MDT');
say $dt->strftime('%A'); # Tuesday
You should be able to use code like the following:
my $t = Time::Piece->strptime($string, "%H:%M:%S %m/%d/%y %Z");
However, on my system at least, I have to change the time zone MST to GMT for it to match; if I leave it as in your example, I get an error:
Perl> my $t = Time::Piece->strptime("05:57:03 08/31/10 DST", "%H:%M:%S %m/%d/%y %Z");
[!] Runtime error: Error parsing time at /usr/local/lib/perl/5.10.0/Time/Piece.pm line 469.
If it works for you, though, you'll have a Time::Piece object, on which you can call e.g. $t->day_of_week for the day of the week as a number, $t->day for e.g. 'Tue', or $t->fullday for e.g. 'Tuesday'.
See the documentation for Time::Piece for details on the methods you can call.

perl help finding proper date format

I need some help trying to figure out how to format dates in perl. I have a working perl script, with a regular expression, that works fine if I use hard coded date strings like this:
my $mon = 'Aug';
my $day = '05';
my $year = '2010';
These vars are used in a regular expression like this:
if ($line =~ m/(.* $mon $day) \d{2}:\d{2}:\d{2} $year: ([^:]+):backup:/)
Now, I need to automate this date portion of the code and use current date systematically.
I looked into perl localtime and tried using unix date and throw them into variables.
I need to have the days of the week, single digit, be padded with '0'. As in today, 'Aug' '05'
'2010' because the input file I am using for the regex has dates like this.
My 2nd try with the unix and formatting is returning numbers, but I need to have them be strings:
my $mon2=`date '+%b'`;
my $day2=`date '+%d'`;
my $year2=`date '+%Y'`;
My test code for playing with date formats:
#!/usr/local/bin/perl -w
use strict;
my $mon = 'Aug';
my $day = '05';
my $year = '2010';
my $mon2=`date '+%b'`;
my $day2=`date '+%d'`;
my $year2=`date '+%Y'`;
print "$mon";
print "$day";
print "$year";
print "$mon2";
print "$day2";
print "$year2";
My Output:
Aug052010Aug
05
2010
I hate to break it to you, but you're reinventing the wheel. All this is implemented quite comprehensively in the DateTime distribution and the DateTime::Format:: family of classes:
use DateTime;
my $dt = DateTime->now;
print 'It is currently ', $dt->strftime('%b %d %H:%M:%S'), ".\n";
prints:
It is currently Aug 05 23:54:01.