I've used the localtime function in Perl to get the current date and time but need to parse in existing dates. I have a GMT date in the following format: "20090103 12:00" I'd like to parse it into a date object I can work with and then convert the GMT time/date into my current time zone which is currently Eastern Standard Time. So I'd like to convert "20090103 12:00" to "20090103 7:00" any info on how to do this would be greatly appreciated.
-
See also: http://stackoverflow.com/questions/95492/how-do-i-convert-a-date – dreeves Jan 05 '09 at 20:53
-
Check these: [http://www.bestofperl.com/how-tos/timezone-conversion-date-time](http://www.bestofperl.com/how-tos/timezone-conversion-date-time) [http://www.bestofperl.com/how-tos/parsing-datetime-strings](http://www.bestofperl.com/how-tos/parsing-datetime-strings) – Pradeep Dec 08 '11 at 05:14
-
The above comment by @Pradeep no longer works. Here's the same links from IA https://web.archive.org/web/20140311045156/http://www.bestofperl.com/how-tos/parsing-datetime-strings.html#comment-3 https://web.archive.org/web/20140715141845/http://www.bestofperl.com:80/how-tos/timezone-conversion-date-time.html – StarGeek May 15 '23 at 20:17
5 Answers
Because the Perl built in date handling interfaces are kind of clunky and you wind up passing around a half dozen variables, the better way is to use either DateTime or Time::Piece. DateTime is the all-singing, all-dancing Perl date object, and you'll probably eventually want to use it, but Time::Piece is simpler and perfectly adequate to this task, has the advantage of shipping with 5.10 and the technique is basically the same for both.
Here's the simple, flexible way using Time::Piece and strptime.
#!/usr/bin/perl
use 5.10.0;
use strict;
use warnings;
use Time::Piece;
# Read the date from the command line.
my $date = shift;
# Parse the date using strptime(), which uses strftime() formats.
my $time = Time::Piece->strptime($date, "%Y%m%d %H:%M");
# Here it is, parsed but still in GMT.
say $time->datetime;
# Create a localtime object for the same timestamp.
$time = localtime($time->epoch);
# And here it is localized.
say $time->datetime;
And here's the by-hand way, for contrast.
Since the format is fixed, a regular expression will do just fine, but if the format changes you'll have to tweak the regex.
my($year, $mon, $day, $hour, $min) =
$date =~ /^(\d{4}) (\d{2}) (\d{2})\ (\d{2}):(\d{2})$/x;
Then convert it to Unix epoch time (seconds since Jan 1st, 1970)
use Time::Local;
# Note that all the internal Perl date handling functions take month
# from 0 and the year starting at 1900. Blame C (or blame Larry for
# parroting C).
my $time = timegm(0, $min, $hour, $day, $mon - 1, $year - 1900);
And then back to your local time.
(undef, $min, $hour, $day, $mon, $year) = localtime($time);
my $local_date = sprintf "%d%02d%02d %02d:%02d\n",
$year + 1900, $mon + 1, $day, $hour, $min;
-
4Even when rolling one's own, one can `use POSIX qw(strftime)` on both Unix and Windows systems from at least Perl 5.6.0 onward. That allows the final "roll-your-own" to become the both shorter and more maintainable: `my $local_date = strftime "%Y%m%d %H:%M\n", localtime($time);`. – pjf Jan 04 '09 at 23:39
-
3$time->localtime->tzoffset AFAICT returns the offset for the current time, not the given time. – ysth Jan 05 '09 at 00:44
-
@ysth Yes, and that's ok unless we want to worry about historical time zone changes, which I sure don't. DST might be important. – Schwern Jan 05 '09 at 07:00
-
It seems `DateTime` module doesn't have date parsing in its repertoire. Here is citation from pod: `This module does not parse dates! Instead, take a look at the various DateTime::Format::* modules on CPAN` – Dfr May 14 '13 at 14:33
-
1@Dfr Yes, this is part of its design. Rather than shipping with a myriad of formatters they are plugins. See [Formatters and Stringification](https://metacpan.org/module/DROLSKY/DateTime-1.03/lib/DateTime.pm#Formatters-And-Stringification) in the docs. The downside is DateTime doesn't even provide the simplest formatting out of the box. The upside is [there are a lot of formatters](https://metacpan.org/search?q=DateTime%3A%3AFormat%3A%3A*). – Schwern May 15 '13 at 21:56
-
@Schwern, You missed the point ysth was raising. It has nothing to do with historical changes. ysth pointed out the offset is different from different dates. In NYC, it's -5 for the dates in the winter and -4 for dates in the in the winter. Your code applied the wrong offset because it used the offset of the current date instead of the offset of the date being modified. [Proof](https://pastebin.com/vpVDuvN1). Fixed. – ikegami Sep 26 '17 at 17:52
-
2
Here's an example, using DateTime and its strptime format module.
use DateTime;
use DateTime::Format::Strptime;
my $val = "20090103 12:00";
my $format = new DateTime::Format::Strptime(
pattern => '%Y%m%d %H:%M',
time_zone => 'GMT',
);
my $date = $format->parse_datetime($val);
print $date->strftime("%Y%m%d %H:%M %Z")."\n";
$date->set_time_zone("America/New_York"); # or "local"
print $date->strftime("%Y%m%d %H:%M %Z")."\n";
$ perl dates.pl
20090103 12:00 UTC
20090103 07:00 EST
If you had wanted to parse localtime, here's how you'd do it :)
use DateTime;
my @time = (localtime);
my $date = DateTime->new(year => $time[5]+1900, month => $time[4]+1,
day => $time[3], hour => $time[2], minute => $time[1],
second => $time[0], time_zone => "America/New_York");
print $date->strftime("%F %r %Z")."\n";
$date->set_time_zone("Europe/Prague");
print $date->strftime("%F %r %Z")."\n";

- 367,544
- 15
- 269
- 518

- 330,807
- 53
- 334
- 373
-
-
Oh, true. I mistakenly assumed he wanted to use localtime output. – Vinko Vrsalovic Jan 05 '09 at 09:09
That's what I'd do ...
#!/usr/bin/perl
use Date::Parse;
use POSIX;
$orig = "20090103 12:00";
print strftime("%Y%m%d %R", localtime(str2time($orig, 'GMT')));
You can also use Time::ParseDate
and parsedate()
instead of Date::Parse
and str2time()
. Note that the de facto standard atm. seems to be DateTime (but you might not want to use OO syntax just to convert a timestamp).
-
Excellent alternative. On an old UNIX, Date::Time was not present, but Date::Parse was. – kbulgrien Jul 06 '20 at 18:40
Take your pick:
- DateTime::* (alternatively, at datetime.perl.org)
- Date::Manip
- Date::Calc (last update in 2004)
There are a zillion others, no doubt, but they're probably the top contenders.

- 730,956
- 141
- 904
- 1,278
-
1
-
But I don't think the activity had occurred by 4th January 2009 when I wrote that comment. However, it is good to know that it is being maintained. Good stable modules don't necessarily need much work as Perl progresses. – Jonathan Leffler Oct 15 '12 at 15:44
use strict;
use warnings;
my ($sec,$min,$hour,$day,$month,$year)=localtime();
$year+=1900;
$month+=1;
$today_time = sprintf("%02d-%02d-%04d %02d:%02d:%02d",$day,$month,$year,$hour,$min,$sec);
print $today_time;

- 169,198
- 16
- 310
- 405
-
This code only prints the current local time. It doesn't answer the question. – nwellnhof Apr 18 '14 at 10:46