Search code examples
perldatetimeparsingdatetime

How do I convert a date/time to epoch time (unix time/seconds since 1970) in Perl?


Given a date/time as an array of (year, month, day, hour, minute, second), how would you convert it to epoch time, i.e., the number of seconds since 1970-01-01 00:00:00 GMT?

Bonus question: If given the date/time as a string, how would you first parse it into the (y,m,d,h,m,s) array?


Solution

  • This is the simplest way to get unix time:

    use Time::Local;
    timelocal($second,$minute,$hour,$day,$month-1,$year);
    

    Note the reverse order of the arguments and that January is month 0. For many more options, see the DateTime module from CPAN.

    As for parsing, see the Date::Parse module from CPAN. If you really need to get fancy with date parsing, the Date::Manip may be helpful, though its own documentation warns you away from it since it carries a lot of baggage (it knows things like common business holidays, for example) and other solutions are much faster.

    If you happen to know something about the format of the date/times you'll be parsing then a simple regular expression may suffice but you're probably better off using an appropriate CPAN module. For example, if you know the dates will always be in YMDHMS order, use the CPAN module DateTime::Format::ISO8601.


    For my own reference, if nothing else, below is a function I use for an application where I know the dates will always be in YMDHMS order with all or part of the "HMS" part optional. It accepts any delimiters (eg, "2009-02-15" or "2009.02.15"). It returns the corresponding unix time (seconds since 1970-01-01 00:00:00 GMT) or -1 if it couldn't parse it (which means you better be sure you'll never legitimately need to parse the date 1969-12-31 23:59:59). It also presumes two-digit years XX up to "69" refer to "20XX", otherwise "19XX" (eg, "50-02-15" means 2050-02-15 but "75-02-15" means 1975-02-15).

    use Time::Local;
    
    sub parsedate { 
      my($s) = @_;
      my($year, $month, $day, $hour, $minute, $second);
    
      if($s =~ m{^\s*(\d{1,4})\W*0*(\d{1,2})\W*0*(\d{1,2})\W*0*
                     (\d{0,2})\W*0*(\d{0,2})\W*0*(\d{0,2})}x) {
        $year = $1;  $month = $2;   $day = $3;
        $hour = $4;  $minute = $5;  $second = $6;
        $hour |= 0;  $minute |= 0;  $second |= 0;  # defaults.
        $year = ($year<100 ? ($year<70 ? 2000+$year : 1900+$year) : $year);
        return timelocal($second,$minute,$hour,$day,$month-1,$year);  
      }
      return -1;
    }