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

I want to convert the timestamp from localtime to GMT. I have legacy code that does this “manually” using Time::Local::timelocal() and gmtime . It works, but I don’t like it and instead use Time::Piece . I used this answer to do this (although they convert in the other direction, 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 does not seem to work properly compared to DST. I live in Germany, so at present (spring / summer, summer time) 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) 

what is right. But for “February 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: gmtime(Time::Local::timelocal($timestamp)) gives the correct offset at 1 hour, and Time::Piece still gives the offset at 2 hours.

Is this a mistake in Time::Piece or am I using it incorrectly?

I know that there are many ways to convert localtime to UTC, but I would like to use Time::Piece because of its simplicity. Plus, I can’t use DateTime because it involves deploying it to a dozen production machines.

+7
datetime dst perl
source share
1 answer

Problem 1

localtime now returned, so localtime->tzoffset() now returns the offset. Change

 my $utc_tp = $local_tp - localtime->tzoffset(); 

to

 my $utc_tp = $local_tp - $local_tp->tzoffset(); 

However, this leaves $utc_tp marked as local time, so you really want to:

 my $utc_tp = gmtime( $local_tp->epoch ); 

Problem 2

Despite its name, $local_tp not 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' ); 
+7
source share

All Articles