there doesn't seem to be a module that takes datetimes as described by ISO
8601 (http://www.cl.cam.ac.uk/~mgk25/iso-time.html) and converts them to a
unix timestamp. several other modules came close, but are missing a few
things.

this module will provide a single function ToUnixTime
(suggestions welcome on a better name) that converts datetimes like:
  19951231T235959
  2001-10-11T11:43:00,0
  2002-07-14T22:34:59+00:00
into unix timestamps.

if a time offset is not present in the string, UTC is used. a different
default timezone may be passed in as an argument like so:
  DateTime::ISO::ToUnixTime($datetime, zone=>'EST5EDT')

comments?

thanks


code follows below if you're interested in implementation:

sub ToUnixTime ($@)
{
  my $date = shift || return;
  my %args = @_;
  my $zone = delete $args{zone} || 'UTC';

  my @match = $date =~ m
  {
    ^
    (\d\d\d\d)            # $1 = YYYY
    -?
    (\d\d)                # $2 = MM
    -?
    (\d\d)                # $3 = DD
    [ T]
    (\d\d)                # $4 = hh
    (?:
       :?
       (\d\d)             # $5 = mm
       (?:
          :?
          (\d\d)          # $6 = ss
          (?:[.,]\d+)?    # fractions of seconds
       )?
    )?
    (?:
       ([+-]?\d\d)        # $7 = timezone hh
       (?:
          :?
          (\d\d)          # $8 = timezone mm
       )?
       |
       Z
    )?
    $
  }x;

  unless (@match)
  {
    $@ = 'unknow date format';
    return;
  }

  my ($YYYY, $MM, $DD, $hh, $mm, $ss, $zhh, $zmm) = @match;
  $mm ||= 0;
  $ss ||= 0;

  require Time::Local;

  ## Time::Local croaks on bad values.
  my $time = eval {
    local $ENV{TZ} = $zone;
    Time::Local::timelocal($ss, $mm, $hh, $DD, $MM-1, $YYYY-1900);
  };
  return if $@;

  delete $ENV{TZ} unless $ENV{TZ};  ## local()izing leaves a "ghost" value.

  ## Adjust for tz offset.
  $time -= $zhh * 60 * 60 if $zhh;
  $time -= $zmm * 60      if $zmm;

  return $time;
}

Reply via email to