Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I convert of the unix date output across multiple time zones to UTC, in Perl?

In Perl, how would one efficiently parse the output of unix's date command, taking into account time zone, and also convert to UTC?

I've read many similar questions on stackoverflow, but few seem to take into account parsing multiple time zones. Instead they seem to set the timezone manually and assume it to stay fixed.

# Example Input Strings:
my @inputs = (
              'Tue Oct 12 06:31:48 EDT 2010',
              'Tue Oct 12 07:49:54 BST 2010',
             );

I tried the following to no avail:

foreach my $input ( @inputs ) {
  my $t = Time::Piece->strptime( $input,
                                 '%a %b %d %T %Z %Y' );
  print $t->cdate, "\n";
}

It seems the problem is the time zone (%Z). Additionally, a time zone field does not seem to exist in Time::Piece, which would require me to write custom code to convert to UTC, which just seems... wrong.

Context: I'm attempting to parse legacy logs from a variety of sources that use the unix date command for timestamps. Ideally, I'd like to convert all timestamps to UTC.

Any help would be greatly appreciated.

like image 558
vlee Avatar asked Oct 12 '10 18:10

vlee


People also ask

Are Unix timestamps always UTC?

A few things you should know about Unix timestamps:Unix timestamps are always based on UTC (otherwise known as GMT). It is illogical to think of a Unix timestamp as being in any particular time zone. Unix timestamps do not account for leap seconds.

Is timestamp stored in UTC?

For timestamp with time zone , the internally stored value is always in UTC (Universal Coordinated Time, traditionally known as Greenwich Mean Time, GMT ). An input value that has an explicit time zone specified is converted to UTC using the appropriate offset for that time zone.

Are epoch timestamps always UTC?

In a computing context, an epoch is the date and time relative to which a computer's clock and timestamp values are determined. The epoch traditionally corresponds to 0 hours, 0 minutes, and 0 seconds (00:00:00) Coordinated Universal Time (UTC) on a specific date, which varies from system to system.


1 Answers

If you know how to disambiguate the TZs, just pop them into a dispatch table:

use strict; use warnings;
use DateTime::Format::Strptime ();

my @inputs = (
    'Tue Oct 12 06:31:48 EDT 2010',
    'Tue Oct 12 07:49:54 BST 2010',
);

my %tz_dispatch = (
    EDT => build_parser( 'EST5EDT' ),
    BST => build_parser( '+0100' ),
    # ... etc
    default => build_parser( ),
);

for my $input (@inputs) {
    my ($parser, $date) = parse_tz( $input, %tz_dispatch );
    print $parser->parse_datetime( $date ), "\n";
}

sub build_parser {
    my ($tz) = @_;

    my %conf = (
        pattern   => '%a %b %d %T %Z %Y',
        on_error  => 'croak',
    );
    @conf{qw/time_zone pattern/} = ($tz, '%a %b %d %T %Y')
    if $tz;

    return DateTime::Format::Strptime->new( %conf );
}

sub parse_tz {
    my ($date, %tz_dispatch) = @_;
    my (@date) = split /\s/, $date;

    my $parser = $tz_dispatch{splice @date, 4, 1};

    return $parser
    ? ($parser, join ' ', @date)
    : ($tz_dispatch{default}, $date);
}
like image 132
Pedro Silva Avatar answered Nov 09 '22 18:11

Pedro Silva