How I can I convert timezones in Perl?
I am trying to convert a date/time GMT 0 to GMT -6 in Perl.
For example, a DHCP Server lease time is in the following format:
2010/02/18 23:48:37
I am trying to convert that time to the Localtime zone (GMT -6) but need it to honor Daylight savings time.
The script below may be overkill, but I a开发者_StackOverflow中文版m not sure how to proceed from here. (Any suggestions would be awsome).
my $TIMESTART;
$TIMESTART = "2010/02/18 23:48:37";
$TIMESTART =~ s/\//-/g;
use DateTime;
use DateTime::TimeZone;
use DateTime::Format::MySQL;
my $dt = DateTime::Format::MySQL->parse_datetime($TIMESTART);
my $tz = DateTime::TimeZone->new( name => 'America/Chicago' );
print $tz->offset_for_datetime($dt) . "\n";
It will output the following lines:
2010-02-18T23:48:37
-21600
I need to be able to add -21600 to the date to get the local time zone of GMT -6 but I am not sure how to approch this.
Call set_time_zone
method 2 times:
my $dt = DateTime::Format::MySQL->parse_datetime($TIMESTART);
$dt->set_time_zone('UTC'); ## set timezone of parsed date time
$dt->set_time_zone('America/Chicago'); ## change timezone in safe way
print DateTime::Format::MySQL->format_datetime($dt),"\n"; ## check the result
How it works:
- when you create
DateTime
object without time zone specified, "floating" time zone is set - first call of
set_time_zone
change time zone toUTC
without conversion - second call of
set_time_zone
changeUTC
toAmerica/Chicago
This will convert UTC time into ETC time. You can also use date/time in any format using +FORMAT parameter of date.
date --date='TZ="ETC" 18:30'
Time::Piece
is a very lightweight piece of code of good quality. Or you can just use built-ins and strftime
and POSIX::strptime
Don't Use Timezones With `DateTime::Format::MySQL->parse_datetime`
There is a very good reason you shouldn't be using this when doing anything relating to timezones. Why? Because it has absolutely no support for timezones whatsoever. Please see the documentation:
All of the parsing methods set the returned DateTime object's time zone to the floating time zone, because MySQL does not provide time zone information. (Source: MetaCPAN: DateTime::Format::MySQL.)
If you DO use this, it will assume your system time zone default. This might not be the timezone you want to convert from! (Although this will work for many people, it only works as long as your servers don't change their default timezone — after that, everything breaks.)
Use `DateTime->new()`, Because It DOES Support TimeZones
Use the constructor that DateTime
provides directly (Source: MetaCPAN: DateTime.):
my $dt = DateTime->new(
year => 1966,
month => 10,
day => 25,
hour => 7,
minute => 15,
second => 47,
nanosecond => 500000000,
time_zone => 'America/Chicago',
);
Convert TimeZones with DateTime
Your starting time zone is whatever you feed into the constructor (i.e., America/Chicago
in the above example). To convert a time to an ending time zone, use set_time_zone()
.
Working Code
In the code below, a time is converted from one timezone to another, and it does this perfectly every time, even you are converting New York time to San Francisco time with a server whose Linux OS is in Singapore time.
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
#!/usr/bin/perl -w
($sec,$min,$hour,$mday,$mon,$year) = gmtime(time+21600);
$year = $year + 1900;
printf("%02d:%02d:%02d %02d.%02d.%04d\n", $hour,$min,$sec,$mday,$mon,$year);
精彩评论