mhooper has asked for the wisdom of the Perl Monks concerning the following question:

I'm looking for a suggestion on how to take a date string like "11:50:45.242 EDT OCT 27 2015" and converting it to UTC in a "2015-10-27 15:50:45.242" format. I've read a few examples but my issue is that original timezone could be on of several North American time zones, in dst or not. thank you

Replies are listed 'Best First'.
Re: Timezone Conversion
by AppleFritter (Vicar) on Oct 27, 2015 at 22:10 UTC

    Howdy there, and welcome to the Monastery!

    There's any number of modules for parsing dates/times on CPAN - Time::ParseDate comes to mind -, and once you've parsed a time, converting it to UTC is easy. That said, maybe I'm missing the obvious, but how do you expect to succeed when you don't know the time zone? 5pm Mountain isn't the same as 5pm Eastern, and if you're only told something happened at "5pm" without a timezone, you cannot say when it actually happened.

    That said, your example - "11:50:45.242 EDT OCT 27 2015" - gives a time zone, EDT (Eastern Daylight Time). Are you able to rely on that being correct? Because if so, the problem's fairly trivial again.

      once you've done parsed(sic!) a time, converting it to UTC is easy

      It is:

      #!/usr/bin/perl use warnings; use strict; use feature qw{ say }; use Time::ParseDate; use Time::Piece; my $string = '11:50:45.242 EDT OCT 27 2015'; my $sec = parsedate($string); my $tp = do { local $ENV{TZ} = 'UTC'; localtime $sec }; my ($microsec) = $string =~ /\.([0-9]+)/; # Microseconds not handled +by the modules. say $tp->strftime("%Y-%m-%d %H:%M:%S.$microsec");

      Note, however, that EDT is ambiguous, and you can get various strange results from times when Eastern Daylight Time is not observed. Timezone names like America/New_York should be preferred.

      لսႽ ᥲᥒ⚪⟊Ⴙᘓᖇ Ꮅᘓᖇ⎱ Ⴙᥲ𝇋ƙᘓᖇ

        Time zone conversion. Fun stuff. Looks easy until you get into it.

        It's not the math that kills you; it's the human complexity element. There's a reason the Time Zone Database is so large.

        If the timezone is given to you as EDT then you're stuck doing your best to avoid or translate ambiguity with what you're given.

        I seem to recall the two keys to doing graceful time conversions are knowing what rules are followed in the creation of the timestamp format you are receiving, and knowing what timezone the target should be.

        I did a time conversion routine at one point where I insisted I should be able to perform the translation in a single computation (and, frankly, I still argue that I should have been able to), but kept wrapping myself around the axle in handling the odd cases. Probably just wasn't my best head-in-the-algorithm day, but the troubles it kept causing me highlighted what I probably should have done from the start

        I finally surrendered and made it a two-step process; convert source time to UTC, then convert UTC to target timezone.

        Not only did I get it right without hassle, but the code was astoundingly easier to read and maintain for the poor sucker who had to work on it the next time they changed the DST rules.

        I begrudgingly accepted the increased computation cost of two conversions for code that was easier to read and maintain.

        Hi choroba, thank you for your response. I tried your code and don't seem to get the conversion to UTC when say executes. I get "2015-10-27 11:50:45.242" not "2015-10-27 15:50:45.242" that I expect, I'm not sure if this is because the code is running on a machine where local timezone is EDT / NewYork or if somehow I've botched your example. Any thoughts?

Re: Timezone Conversion
by jeffa (Bishop) on Oct 28, 2015 at 16:37 UTC

    The twist that makes this otherwise fairly trivial problem complicated is having to respect Daylight Savings Time. I once had to convert times given in UTC to their local equivalents for all of the US and Canada. We had to query a service in order to determine if the given city respected Daylight Savings Time or not, but after that we could use a hash to provide a close enough approximation. Since you want to convert to UTC, you most likely will need not the following code. But in the event you (or others who are reading) need to convert to local US and Canada time zones, the following can help. Just note that the data in the hash was determined 3 years ago and some areas might have changed.

    use strict; use warnings; use Data::Dumper; use DateTime; use Time::ParseDate; use DateTime::TimeZone; our %TIMEZONES = ( # DST '-3.5Y' => 'America/St_Johns', '-4Y' => 'America/Halifax', '-5Y' => 'America/New_York', '-6Y' => 'America/Chicago', '-7Y' => 'America/Denver', '-8Y' => 'America/Los_Angeles', '-9Y' => 'America/Anchorage', '-10Y' => 'America/Adak', # NOT DST '-11N' => 'Pacific/Midway', '-10N' => 'Pacific/Honolulu', '-8N' => 'Pacific/Pitcairn', '-7N' => 'America/Phoenix', '-6N' => 'America/Managua', '-4N' => 'America/St_Vincent', '0N' => 'America/Danmarkshavn', '9N' => 'Pacific/Palau', '10N' => 'Pacific/Truk', '11N' => 'Pacific/Efate', '12N' => 'Pacific/Wallis', ); sub timezone { my ($utc_offset,$is_dst) = @_; return DateTime::TimeZone->new( name => $TIMEZONES{$utc_offset . $ +is_dst} ); } my $input = '11:50:45.242 EDT OCT 27 2015'; my $epoch = parsedate( $input ); my $dt = DateTime->from_epoch( epoch => $epoch ); $dt->set_time_zone( timezone( 0, 'N' ) ); print $dt->strftime( '%Y-%m-%d %H:%M:%S' ), $/;
    So for your usage, the following would suffice:
    $dt->set_time_zone( timezone( 0, 'N' ) );
    But if you wanted to convert to some local time in Indiana, it could be any of the following:
    $dt->set_time_zone( timezone( -5, 'Y' ) ); # Central with DST $dt->set_time_zone( timezone( -6, 'N' ) ); # Eastern without DST $dt->set_time_zone( timezone( -6, 'Y' ) ); # Eastern with DST
    And you have to know beforehand (via some lookup table provided by some external source) what the rules are for the city you are converting to. This all makes you wonder why we still have DST, and if fact many people would like to abolish it.

    P.S. My co-worker that helped derive this solution was going to release this as TimeZone::CloseEnough.

    jeffa

    L-LL-L--L-LL-L--L-LL-L--
    -R--R-RR-R--R-RR-R--R-RR
    B--B--B--B--B--B--B--B--
    H---H---H---H---H---H---
    (the triplet paradiddle with high-hat)
    
Re: Timezone Conversion
by mhooper (Novice) on Oct 29, 2015 at 13:02 UTC

    Thank you to one and all for responding. I should have stated that the timestamps are coming from known places, so I can rely on them, but the administrators at each site want their information in their own local timezone (respecting DST for example) but that my warehouse wants to put all of their data into UTC for aggregation purposes. Again, thanks to all for helping me out here.