How to convert unix epoch time to readable format in perl - 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.

Related

Perl Format dates

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

How to make Time::Piece respect DST when converting localtime to UTC?

I want to convert a timestamp from localtime to GMT. I have legacy code that does this "manually" with Time::Local::timelocal() and gmtime. It works, but I don't like it and wanted to use Time::Piece instead. I used this answer to do so (albeit they are converting the other way round, but I was able to replace + with - :-)).
This is my code:
#!/usr/bin/env perl
use strict;
use warnings;
use Time::Local;
use Time::Piece;
use POSIX qw(strftime);
sub local_to_utc_timelocal
{
my $local_ts = shift;
my ( $year, $mon, $mday, $hour, $min, $sec )
= ( $local_ts =~ /(\d\d)-(\d\d)-(\d\d) (\d\d):(\d\d):(\d\d)/ );
my $local_secs = Time::Local::timelocal( $sec, $min, $hour, $mday, $mon - 1, $year );
return POSIX::strftime( '%y-%m-%d %H:%M:%S', gmtime($local_secs) );
}
sub local_to_utc_timepiece
{
my $local_ts = shift;
my $local_tp = Time::Piece->strptime( $local_ts, '%y-%m-%d %H:%M:%S' );
my $utc_tp = $local_tp - localtime->tzoffset(); # ***
return $utc_tp->strftime('%y-%m-%d %H:%M:%S');
}
my $local;
# DST in effect (April 19 2016):
$local = '16-04-19 14:30:00';
print "DST in effect:\n";
printf("utc(%s) = %s (using timelocal)\n", $local, local_to_utc_timelocal($local));
printf("utc(%s) = %s (using timepiece)\n\n", $local, local_to_utc_timepiece($local));
# DST NOT in effect (Feb 19 2016):
$local = '16-02-19 14:30:00';
print "DST NOT in effect:\n";
printf("utc(%s) = %s (using timelocal)\n", $local, local_to_utc_timelocal($local));
printf("utc(%s) = %s (using timepiece)\n", $local, local_to_utc_timepiece($local));
Unfortunately the Time::Piece code doesn't seem to work properly wrt DST. I'm living in Germany, so currently (spring/summer, DST in effect) we are UTC+2. For "April 19 2016" the above code gives:
DST in effect:
utc(16-04-19 14:30:00) = 16-04-19 12:30:00 (using timelocal)
utc(16-04-19 14:30:00) = 16-04-19 12:30:00 (using timepiece)
which is correct. But for "Feb 19 2016" (when we are UTC+1) the same code gives:
DST NOT in effect:
utc(16-02-19 14:30:00) = 16-02-19 13:30:00 (using timelocal)
utc(16-02-19 14:30:00) = 16-02-19 12:30:00 (using timepiece)
That is: The gmtime(Time::Local::timelocal($timestamp)) gives correct 1 hour offset while Time::Piece still gives 2 hours offset.
Is this a bug in Time::Piece or do I use it wrongly?
I know there are plenty of ways to convert localtime to UTC but I'd like to use Time::Piece because of its simplicity. Plus I cannot use DateTime because that would involve deploying it on a dozen of production machines.
Problem 1
localtime returns now, so localtime->tzoffset() returns the offset for now. Change
my $utc_tp = $local_tp - localtime->tzoffset();
to
my $utc_tp = $local_tp - $local_tp->tzoffset();
However, that leaves $utc_tp flagged as a localtime, so you really want:
my $utc_tp = gmtime( $local_tp->epoch );
Problem 2
Despite its name, $local_tp is not a local time, so $local_tp->tzoffset() is zero. Change
Time::Piece->strptime( $local_ts, '%y-%m-%d %H:%M:%S' )
to
localtime->strptime( $local_ts, '%y-%m-%d %H:%M:%S' );

Perl Incorrect day generated by localtime

Today I find following perl script running incorrect.
Current actual datetime is 20140814 13:19
But it returns: 2014-7-14-13-19-15 (the month value 7 is 1 less than actual value 8)
MY OS: win7
sub GetFileNameDate {
my ($sec,$min,$hour,$day,$month,$yr19,#rest) = localtime;
return sprintf "%s-%s-%s-%02d-%02d-%02d", ($yr19 + 1900), $month, $day, $hour, $min, $sec;
}
It is not incorrect it is like the month values starts from 0
sub GetFileNameDate {
my ($sec,$min,$hour,$day,$month,$yr19,#rest) = localtime;
return sprintf "%s-%s-%s-%02d-%02d-%02d", ($yr19 + 1900), ($month +1), $day, $hour, $min, $sec;
}
$month is the month itself, in the range 0..11 with 0 indicating January and 11 indicating December.
You can check the manual
That is correct according to the docs for localtime:
$mday is the day of the month and $mon the month in the range 0..11, with 0 indicating January and 11 indicating December. This makes it easy to get a month name from a list.
However, to simplify your goal, I'd recommend using Time::Piece:
use strict;
use warnings;
use Time::Piece;
sub GetFileNameDate {
return localtime->strftime("%Y-%m-%d-%H-%M-%S");
}
print GetFileNameDate(), "\n";
Outputs:
2014-08-13-23-42-56
Did you perhaps want POSIX::strftime?
use POSIX qw( strftime );
print strftime "%Y-%m-%d-%H-%M-%S", localtime;

How do I convert local time to a Unix timestamp in Perl?

For example: from date: 10/02/2010
How do I convert an equal timestamp for 10/02/2010 00:00:00 in Perl?
I can't use local time or time .. is there another way to achieve this?
You can use the Time::Local core module:
use Time::Local 'timelocal';
my ($d, $m, $y) = split '/', '10/02/2010';
my $time = timelocal(0, 0, 0, $d, $m-1, $y);
Note that the month argument for timelocal() is in the range 0..11.
Without localtime():
use Time::Local;
$time = timelocal($sec, $min, $hour, $mday, $mon, $year);
(See perldoc.)
A standard way would be something like:
use POSIX;
use strict;
use warnings;
my $sec = 0;
my $min = 0;
my $hour = 0;
my $day = 10;
my $mon = 2 - 1;
my $year = 2010 - 1900;
my $wday = 0;
my $yday = 0;
my $unixtime = mktime ($sec, $min, $hour, $day, $mon, $year, $wday, $yday);
print "$unixtime\n";
my $readable_time = localtime($unixtime);
print "$readable_time\n"
(From Converting Unix time and readable time with Perl)
You could use Date::Parse:
use Date::Parse;
print str2time('10/02/2010 00:00:00');
On my machine this prints 1285970400, which corresponds to October 2nd, 2010 (I live in +1 GMT with +1 Wintertime.)
I think you want the built-in module Time::Local.
The DateTime module should be helpful here. In particular, I believe the DateTime::Format::Natural module can parse a user-supplied date string. From there, you have a DateTime object and can print it out or transform it as you like.
Depending on where your initial date is coming from you might be able to parse it using
Date::Manip
and calling
ParseDate("10/02/2010")
You can then take that output and convert it into whatever format you wish.

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