Displaying 12-h time in Perl using DateTime - perl

This perl script produces a datestamp and timestamp.
Is there a simple way to display the time in a 12 hour format with AM/PM displayed?
use DateTime;
use DateTime::TimeZone;
my $tz = DateTime::TimeZone->new( name => 'Pacific/Honolulu' );
my $dt = DateTime->now(time_zone =>'Pacific/Honolulu');
my $offset = $tz->offset_for_datetime($dt);
$timestamp = $dt->hms(':');
$datestamp = $dt->mdy('/');
print "$datestamp at $timestamp\n";

Most date-time modules will provide access to the C function strftime or a re-implementation of it. In format specifications provided to strftime, you can use the following patterns:
%I: The hour as a decimal number using a 12-hour clock.
%l: The hour as a decimal number using a 12-hour clock. Single digits are preceded by a blank.
%p: Either "AM" or "PM".
%P: Either "am" or "pm".
DateTime objects have a method called strftime. For example,
$ perl -e'
use DateTime qw( );
my $now = DateTime->now( time_zone => "local" );
CORE::say $now->strftime("%Y/%m/%d %I:%M:%S %p %z");
'
2019/06/02 09:45:37 PM -0400
As #Nilesh Bhimani tried to point out, the DateTime module is rather heavy, and it's not required for this task (especially if you want to use local time or UTC) because the POSIX module provides strftime as well. For example,
$ perl -e'
use POSIX qw( strftime );
my $now = time;
CORE::say strftime("%Y/%m/%d %I:%M:%S %p %z", localtime($now));
'
2019/06/02 09:45:37 PM -0400

#!/usr/local/bin/perl
use POSIX qw(strftime);
my $datestring = strftime "%a %b %e %H:%M:%S %Y %P", localtime;
printf "date and time - $datestring\n";
my $datestring = strftime "%a %b %e %H:%M:%S %Y %P", gmtime;
printf "date and time - $datestring\n";

Related

How to format local time to mm/dd/yyyy HH:MM:SS AM/PM in Perl

I need to convert the local time to exact format as mm/dd/yyyy HH:MM:SS AM/PM.
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime();
By using strftime of POSIX module you can get the desire result:
use POSIX qw/strftime/;
print strftime('%d-%m-%Y %I:%M:%S %p',localtime);
I would suggest the Time::Piece module (which is core):
use Time::Piece;
print localtime -> strftime("%d-%m-%Y %I:%M:%S %p");
One option:
use POSIX qw(strftime);
my $date = strftime "%m/%d/%Y %I:%M:%S %p", localtime;
print $date;
See it in action
You could use the powerfull DateTime library and it's strftime-function.
use DateTime;
my $dt = DateTime->now(); # Defaults to now
my $string = $dt->strftime("%m/%d/%Y %l:%M:%S %p");
print "The Time: $string\n";

How to convert unix epoch time to readable format in perl

How do I convert 1461241125.31307 in perl. I tried:
use Date::Parse;
$unix_timestamp = '1461241125.31307';
my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime($unix_timestamp);
$mon += 1;
$year += 1900;
$unix_timestamp_normal = "$year-$mon-$mday $hour:$min:$sec";
result: 2016-4-21 5:18:45 (no padding of hour)
How do I pad it and make it GMT. I want the result to say 2016-04-21 12:18:45
Thanks for the answers folks.
use DateTime;
$unix_timestamp = '1461241125.31307';
my $dt = DateTime->from_epoch(epoch => $unix_timestamp);
print $dt->strftime('%Y-%m-%d %H:%M:%S'),"\n";
Easiest way:
print scalar localtime $unix_timestamp;
Documentation: http://perldoc.perl.org/functions/localtime.html
For GMT, use gmtime:
print scalar gmtime $unix_timestamp;
Documentation: http://perldoc.perl.org/functions/gmtime.html (Basically says: Everything like localtime, but outputs GMT time.)
For custom formats, try DateTime:
use DateTime;
my $dt = DateTime->from_epoch(epoch => $unix_timestamp);
print $dt->strftime('%Y-%s');
See http://search.cpan.org/perldoc?DateTime for all options. Lots of formats could be created even more easily using the predefined DateTime Formatters: http://search.cpan.org/search?query=DateTime%3A%3AFormat&mode=all
use POSIX qw( strftime );
my $epoch_ts = '1461241125.31307';
say strftime('%Y-%m-%d %H:%M:%S', gmtime($epoch_ts));
Use gmtime instead of localtime
perldoc -f gmtime :
gmtime EXPR
gmtime Works just like "localtime" but the returned values are localized
for the standard Greenwich time zone.
Note: When called in list context, $isdst, the last value returned
by gmtime, is always 0. There is no Daylight Saving Time in GMT.
Portability issues: "gmtime" in perlport.

Using strptime to parse timestamp relative to the local time

I am trying to do some date calculation relative to the current local time.
For example:
use feature qw(say);
use strict;
use warnings;
use Time::Piece;
my $fmt = '%Y-%m-%d_%H:%M:%S';
my $timestamp = "2015-04-12_11:07:27";
# This gives incorrect $t1 relative to localtime
my $t1 = Time::Piece->strptime( $timestamp, $fmt );
my $t2 = localtime;
say "Local time: " . localtime;
say "Local time epoch: " . time;
say $t1->epoch();
say $t2->epoch();
my $timestamp1 = $t1->strftime( $fmt );
my $timestamp2 = $t2->strftime( $fmt );
say $timestamp1;
say $timestamp2;
my $delta = $t2 - $t1;
say $delta;
A sample output:
Local time: Sun Apr 12 12:21:49 2015
Local time epoch: 1428834109
1428836847
1428834109
2015-04-12_11:07:27
2015-04-12_12:21:49
-2738
Which clearly gives the a wrong time difference of -2738. ( It should be a positive number)
If the date-time you parse has no time zone information, it's assumed to be UTC. You can see this by adding the following two lines in your script:
say "tzo1 = ",$t1->tzoffset;
say "tzo2 = ",$t2->tzoffset;
In Paris, the above outputs the following:
tzo1 = 0
tzo2 = 7200
You can override the default to be the local time zone by using the undocumented feature of using localtime instead of Time::Piece as the invocant.
$ perl -MTime::Piece -E'
say Time::Piece->strptime("2015-04-12_11:07:27", "%Y-%m-%d_%H:%M:%S")->tzoffset;
say localtime ->strptime("2015-04-12_11:07:27", "%Y-%m-%d_%H:%M:%S")->tzoffset;
'
0
7200
Doing that minor change gives the answer you were expecting.
$ perl -MTime::Piece -E'
say localtime->strptime("2015-04-12_11:07:27", "%Y-%m-%d_%H:%M:%S") - localtime;
'
5524
I think this can be done using Date::Time :
use feature qw(say);
use strict;
use warnings;
use DateTime;
use DateTime::Format::Strptime;
use DateTime::Duration;
my $strp = DateTime::Format::Strptime->new(
pattern => '%Y-%m-%d_%H:%M:%S',
time_zone => 'local',
);
my $timestamp = "2015-04-12_11:07:27";
my $dt1 = $strp->parse_datetime( $timestamp );
my $dt2 = DateTime->now();
say $dt2->subtract_datetime_absolute( $dt1 )->seconds();

Convert time in GMT to current time zone in perl

I want to convert GMT time string to my system time zone.
Ex.
Tue Nov 04 22:03:03 2014 GMT
My machine time zone is PST, so output should be : 2014-11-04 14:03:03 PST
I can do this in bash but could not find any solution for perl.
Bash solution=> timestamp_local=date "+%Y-%m-%d %H:%M:%S %Z" -d "$timestamp_GMT"
Anyone have solution in perl?
PS: I have to process a huge file ( around 100-200MB of text file ). So, I want a optimized solution.
Simple enough with DateTime and friends.
#!/usr/bin/perl
use strict;
use warnings;
use 5.010;
use DateTime::Format::Strptime;
use DateTime;
my $format = '%a %b %d %H:%M:%S %Y %Z';
my $time_string = 'Tue Nov 04 22:03:03 2014 GMT';
my $dt_p = DateTime::Format::Strptime->new(
pattern => $format,
time_zone => 'UTC',
);
my $time = $dt_p->parse_datetime($time_string);
say $time->strftime('%a %b %d %H:%M:%S %Y %Z');
$time->set_time_zone('America/Los_Angeles');
say $time->strftime('%a %b %d %H:%M:%S %Y %Z');
Update: And this old answer shows how to do something very similar with the core module Time::Piece.
POSIX library should be enough to do this;
use strict;
use feature qw/say/;
use POSIX qw(strftime tzset);
say strftime("%Y %d %m %H:%M:%S GMT", gmtime(time)); # GMT
say strftime("%Y %d %m %H:%M:%S %Z", localtime(time)); # Local Time
# Set to custom timezone
$ENV{TZ} = 'America/Los_Angeles';
tzset;
say strftime("%Y %d %m %H:%M:%S %Z", localtime(time)); # Custom Zone

How can I change the timezone of a datetime value in Perl?

Using this function:
perl -e 'use Time::Local; print timelocal("00","00","00","01","01","2000"),"\n";'
It will return an epochtime - but only in GMT - if i want the result in GMT+1 (which is the systems localtime(TZ)), what do i need to change?
Thanks in advance,
Anders
use DateTime;
my $dt = DateTime->now;
$dt->set_time_zone( 'Europe/Madrid' );
There is only one standard definition for epochtime, based on UTC, and not different epochtimes for different timezones.
If you want to find the offset between gmtime and localtime, use
use Time::Local;
#t = localtime(time);
$gmt_offset_in_seconds = timegm(#t) - timelocal(#t);
While Time::Local is a reasonable solution, you may be better off using the more modern DateTime object oriented module. Here's an example:
use strict;
use DateTime;
my $dt = DateTime->now;
print $dt->epoch, "\n";
For the timezones, you can use the DateTime::TimeZone module.
use strict;
use DateTime;
use DateTime::TimeZone;
my $dt = DateTime->now;
my $tz = DateTime::TimeZone->new(name => "local");
$dt->add(seconds => $tz->offset_for_datetime($dt));
print $dt->epoch, "\n";
CPAN Links:
DateTime
You just need to set the timezone. Try:
env TZ=UTC+1 perl -e 'use Time::Local; print timelocal("00","00","00","01","01","2000"),"\n";'
Time::Local::timelocal is the inverse of localtime. The result will be in your host's local time:
$ perl -MTime::Local -le \
'print scalar localtime timelocal "00","00","00","01","01","2000"'
Tue Feb 1 00:00:00 2000
Do you want the gmtime that corresponds to that localtime?
$ perl -MTime::Local' -le \
'print scalar gmtime timelocal "00","00","00","01","01","2000"'
Mon Jan 31 23:00:00 2000
Do you want it the other way around, the localtime that corresponds to that gmtime?
$ perl -MTime::Local -le \
'print scalar localtime timegm "00","00","00","01","01","2000"'
Tue Feb 1 01:00:00 2000
An other example based on DateTime::Format::Strptime
use strict;
use warnings;
use v5.10;
use DateTime::Format::Strptime;
my $s = "2016-12-22T06:16:29.798Z";
my $p = DateTime::Format::Strptime->new(
pattern => "%Y-%m-%dT%T.%NZ",
time_zone => "UTC"
);
my $dt = $p->parse_datetime($s);
$dt->set_time_zone("Europe/Berlin");
say join ' ', $dt->ymd, $dt->hms; # shows 2016-12-22 07:16:29
The Algorithm
If you want to change a time value from one timezone to another timezone, you must be able to indicate both timezones.
After all, if you set if you want to convert "12:30" to GMT or US/Eastern or Venezuelan time, which means adding/subtracting some amount of hours or hours and minutes, you need to know what timezone is the starting time zone, otherwise, the calculation won't know how much to add or subtract.
If you use DateTime->now;, the timezone is defaulted to the system-time, which may not be the timezone you want to convert from.
In the below code, I demonstrate how to initialize the datetime object to the right starting timezone (fromtimezone) and how to convert that time to the ending timezone (totimezone)...
Working Code
I could not find a Perl sandbox online with the DateTime CPAN module installed.
use strict;
use DateTime;
sub convertTimeZonesForTime {
my ($args) = #_;
my $time = $args->{time};
my $date = $args->{date};
my $totimezone = $args->{totimezone};
my $fromtimezone = $args->{fromtimezone};
my $format = $args->{format} || '%H:%M:%S';
my ($year, $month, $day) = map {int $_} split('-', $date);
my ($hour, $minute, $second) = map {int $_} split(':', $time);
$year ||= 1999 if !defined $year;
$month ||= 1 if !defined $month;
$day ||= 1 if !defined $day;
$hour ||= 12 if !defined $hour;
$minute ||= 30 if !defined $minute;
$second ||= 0 if !defined $second;
my $dt = DateTime->new(
year=>$year,
month=>$month,
day=>$day,
hour=>$hour,
minute=>$minute,
second=>$second,
time_zone => $fromtimezone,
);
my $formatter = new DateTime::Format::Strptime(pattern => $format);
$dt->set_formatter($formatter);
$dt->set_time_zone($totimezone);
return "$dt";
}
print(convertTimeZonesForTime({
'totimezone'=>'America/Denver',
'fromtimezone'=>'US/Eastern',
'time'=>'12:30:00',
}));
Output:
10:30:00