Simple way to format date - perl

I wrote a perl script to get datetime.
It do work but I do wonder if there any easier way to format date as output.
#!/usr/bin/perl
use DateTime;
my $dt = DateTime->now( time_zone => 'local' );
$myTimeStamp = $dt->subtract( days => 1 );
$myYear = $myTimeStamp->year;
$myMonth = $myTimeStamp->month;
if ( length( $myMonth ) == 1 ) {
$myMonth = "0$myMonth";
}
$myDay = $myTimeStamp->day;
if ( length( $myDay ) == 1 ) {
$myDay = "0$myDay";
}
$myHour = $myTimeStamp->hour;
if ( length( $myHour ) == 1 ) {
$myHour = "0$myHour";
}
#$myDir = "/var/tmp/logs/$myYear/$myMonth/$myYear$myMonth-";
print "--> $myYear $myMonth $myDay $myHour\n";
# --> 2012 02 28 02
exit 0;

DateTime provides the format_cldr method for this:
use DateTime;
my $myTimeStamp = DateTime->now->subtract( days => 1 );
printf "--> %s\n", $myTimeStamp->format_cldr('yyyy MM dd HH');
# --> 2012 02 28 02

Sure, use POSIX module:
The POSIX module permits you to access all (or nearly all) the
standard POSIX 1003.1 identifiers.
Example:
use POSIX;
print POSIX::strftime('%d-%m-%Y %H:%M:%S', localtime());

First of all always use strict; and use warnings; at the start of your program and declare all your variables close to their first use. This applies especially if you are seeking help as it will find a lot of simple errors that aren't immediately obvious.
It is best to use printf if you want to zero-pad any output. There is also no need to extract the date fields to separate variables. Is the output you have shown the one you ultimately want? This program does the same thing as the code you have posted.
use strict;
use warnings;
use DateTime;
my $myTimeStamp = DateTime->now->subtract( days => 1 );
printf "--> %04d %02d %02d %02d\n", map $myTimeStamp->$_, qw/year month day hour/;
OUTPUT
--> 2012 02 28 12

For re-formatting dates, as noted, there is the POSIX core module. You would be remiss not to look at the core module Time::Piece too, which not only delivers strftime() but also strptime() to provide very flexible date/time parsing. Time::Piece appeared in Perl core in 5.9.5.

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

convert perl timestamp to human readable

I am reading a log file which contains time stamps which I want to convert to human readable.
In this command, $1 contains a time stamp (like this 1403457192.663): $temp = localtime->mon($1) but instead of storing the month, $temp contains the same timestamp that was input. What am I doing wrong?
You're close. The time should be passed to the localtime function, not the mon method.:
$temp = localtime($1)->mon; # 6
You can use strftime with this to turn it into any arbitrary format
localtime($1)->strftime("%b %d %a"); # Jun 22 Sun
Or if you're not picky about the format you can just stringify it:
$temp = localtime($1);
print "$temp\n"; # Sun Jun 22 13:13:12 2014
This assumes that Time::Piece is loaded.
I'd simply go with
$ perl -E'
use POSIX qw( strftime );
say strftime("%Y/%m/%d %H:%M:%S", localtime(1403457192.663));
'
2014/06/22 13:13:12
But you're using Time::localtime. That module overrides the localtime builtin, so you need a slight modification if you use that.
Either avoid using Time::localtime's localtime
$ perl -E'
use POSIX qw( strftime );
use Time::localtime qw( localtime );
say strftime("%Y/%m/%d %H:%M:%S", CORE::localtime(1403457192.663));
'
2014/06/22 13:13:12
or flatten an existing Time::localtime object.
$ perl -E'
use POSIX qw( strftime );
use Time::localtime qw( localtime );
my $tm = localtime(1403457192.663);
say strftime("%Y/%m/%d %H:%M:%S", #$tm);
'
2014/06/22 13:13:12
All of these solutions lose the millisecond precision. If it's relevant, you'll have to extract it from the original input and reinsert it in the output.
For formatting dates most system strftime manual pages will list a few "shortcuts" to get you certain "standard" formats.
e.g. %F is equivalent to ā€œ%Y-%m-%dā€.
~/% perl -MPOSIX -E'say strftime"%D",localtime'
06/25/14
~/% perl -MPOSIX -E'say strftime"%F",localtime'
2014-06-25
These can make using "ye olde" strftime easier ;-)
Perl since 5.10 now contains Time::Piece. This makes it the official way to handle time in Perl. Or, about as official as something gets in Perl. Since it's always available, you might as well learn to use that:
use strict;
use warnings;
use Time::Piece;
use Time::Seconds; # More time fun!
my $time = Time::Piece->new; # Gets the current timestamp
my $month = $time->mon(); # Month from 1 to 12
my $month = $time->month(); # Abbreviation of the name of month
my $month = $time->fullmonth(); # Full name of the month
my $time = $time + (ONE_DAY * 30) # Add thirty days to the time
my $date = $time->mdy # The date 30 days from now.

How can I convert a date time and time zone correctly?

I have done some searching and I'm not sure how to get this converted correctly using core Perl modules. I have 2013-10-22T19:31:00Z and want to get 10/22/2013 and the time in US Central time.
Here's a solution using just core modules (well, you need to have at least perl 5.8):
use strict;
use POSIX qw(tzset strftime);
use Time::Local qw(timegm);
my $iso_time = "2013-10-22T19:31:00Z";
my $formatted_time;
{
local $ENV{TZ} = "America/Chicago";
tzset;
if (my($y,$m,$d,$H,$M,$S) = $iso_time =~ m{^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})Z$}) {
$formatted_time = strftime '%m/%d/%Y %H:%M:%S', localtime timegm $S,$M,$H,$d,$m-1,$y;
} else {
# invalid ISO date, do something
}
}
tzset; # restore default time zone handling
warn $formatted_time, "\n"; # output is "10/22/2013 14:31:00"
A word about the TZ trick: by setting the environment variable TZ some time-related libc functions (e.g. localtime) use that time zone instead of the default time zone. If the TZ environment variable is set within a program, then tzset() has to be called to adjust the internal time-related data structures. And don't forget to call tzset() again to restore the data structures again.
This should work on most Unix system, but may or may not work on a Windows system.
use DateTime::Format::RFC3339 qw( );
use DateTime::Format::Strptime qw( );
my $in_dt_format = DateTime::Format::RFC3339->new();
my $out_dt_format = DateTime::Format::Strptime->new(
pattern => '%m/%d/%Y %H:%M:%S',
on_error => 'croak',
);
my $dt = $in_dt_format->parse_datetime('2013-10-22T19:31:00Z');
$dt->set_time_zone('America/Chicago');
say $out_dt_format->format_datetime($dt); # 10/22/2013 14:31:00
Standard Perl modules?
That would include Time::Piece that's been part of Perl since 5.10.
#! /usr/bin/env perl
use strict;
use warnings;
use feature qw(say);
use Time::Piece;
my $date = "2013-10-22T19:31:00Z";
my $time = Time::Piece->strptime ( $date, "%Y-%m-%dT%H:%M:%SZ" );
$time = localtime($time); # Converts time to local time
say $time->mdy("/");
This prints out:
10/22/2013
That wacky "%Y-%m-%dT%H:%M:%SZ" string represents the format of your time input. You can find it in your manage for strftime.
%Y: Four digit year
%m: Month from 01 - 12
%d: Day from 01 - 31
%H: Hour from 00 - 23
%M: Minute from 00 - 59
%S: Second from 00 - 59

How to convert text date to timestamp?

How to convert date in text format:
23.10.2011 11:35:00
to timestamp ?
Using Time::Local , you can do:
use Time::Local;
my $date = '23.10.2011 11:35:00';
my ($mday,$mon,$year,$hour,$min,$sec) = split(/[\s.:]+/, $date);
my $time = timelocal($sec,$min,$hour,$mday,$mon-1,$year);
print $time,"\n",scalar localtime $time;
Output:
1319362500
Sun Oct 23 11:35:00 2011
I'd look into DateTime and the parsing modules.
perl -MDateTime::Format::Strptime -le'$strp = DateTime::Format::Strptime->new( pattern => "%d.%m.%Y %T", time_zone => "local"); $dt = $strp->parse_datetime("23.10.2011 11:35:00"); print $dt->epoch'
1319384100 at -e line 1.
Same as above, but not a one-liner:
use DateTime::Format::Strptime;
my $strp = DateTime::Format::Strptime->new(
pattern => '%d.%m.%Y %T',
time_zone => 'local',
);
my $dt = $strp->parse_datetime('23.10.2011 11:35:00');
print $dt->epoch;
Using Date::Parse in Perl is very elegante option too.
Maybe someone will found this useful:
$gmtdate = 'Jul 12 00:12:26 2021 GMT';
my $timestamp = str2time($gmtdate);
Not sure why the Time::Piece answer was deleted. Maybe because it (Time::Piece) has its quirks. But it's more powerful than Date::Parse (although less powerful than DateTime, but some say it covers most of the needs), it's a core module, and you don't have to parse the string as with Time::Local. But datetime math is apparently not DST-safe.
Long story short:
use Time::Piece;
my $tp = Time::Piece->strptime("23.10.2011 11:35:00",
"%d.%m.%Y %H:%M:%S");
# or this way (if the timestamp is in the local time zone):
# $tp = localtime->strptime("23.10.2011 11:35:00",
# "%d.%m.%Y %H:%M:%S");
print $tp;
More on creating Time::Piece objects here.

Parsing dateTime in perl correct to micro/nano seconds

Im looking for a perl module which takes a date string like this "Nov 23 10:42:31.808381" and its format something like "%b %d ...." this and get me a dateTime object/or print it into another format specified in the same way. Time::Piece doesnt have resolution upto nano seconds. Is there any module which will help me?
Im using perl 5.8 (this doesnt have named backreferences)
DateTime::Format::Strptime has support for microseconds and nanoseconds.
Your format is slightly strange as it doesn't include a year. I've added one you make this demo code work.
#!/usr/bin/perl
use strict;
use warnings;
use DateTime::Format::Strptime;
my $strp = DateTime::Format::Strptime->new(
pattern => '%b %d %Y %H:%M:%S.%6N',
on_error => 'croak',
);
my $string = 'Nov 23 2010 10:42:31.808381';
my $dt = $strp->parse_datetime($string);
print $dt->microsecond;
"Nov 23 10:42:31.808381" -- is microseconds, not nanoseconds
If you need microseconds, you must use Time::HiRes; module and gettimeofday method in it.