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

4,458

Solution 1

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;
}

Solution 2

If you're using the DateTime module, you can call the epoch() method on a DateTime object, since that's what you think of as unix time.

Using DateTimes allows you to convert fairly easily from epoch, to date objects.

Alternativly, localtime and gmtime will convert an epoch into an array containing day month and year, and timelocal and timegm from the Time::Local module will do the opposite, converting an array of time elements (seconds, minutes, ..., days, months etc.) into an epoch.

Solution 3

To parse a date, look at Date::Parse in CPAN.

Solution 4

I know this is an old question, but thought I would offer another answer.

Time::Piece is core as of Perl 5.9.5

This allows parsing of time in arbitrary formats via the strptime method.

e.g.:

my $t = Time::Piece->strptime("Sunday 3rd Nov, 1943",
                              "%A %drd %b, %Y");

The useful part is - because it's an overloaded object, you can use it for numeric comparisons.

e.g.

if ( $t < time() ) { #do something }

Or if you access it in a string context:

print $t,"\n"; 

You get:

Wed Nov  3 00:00:00 1943

There's a bunch of accessor methods that allow for some assorted other useful time based transforms. https://metacpan.org/pod/Time::Piece

Solution 5

$ENV{TZ}="GMT";
POSIX::tzset();
$time = POSIX::mktime($s,$m,$h,$d,$mo-1,$y-1900);
Share:
4,458
Jason Yost
Author by

Jason Yost

Updated on July 09, 2022

Comments

  • Jason Yost
    Jason Yost almost 2 years

    I am working with jQuery mobile and using the HTML5 audio tag. I have a single button to trigger the playing of the audio on the page. I trigger the audio playback with the following:

    $('#voice').live("click", function() {
        $('#speech').trigger("play");
    });
    

    The audio tag is simple:

    <audio src="path_to_media" id="speech"></audio>
    

    When a page is first loaded the audio works perfectly however the audio tag and source on not updated on page transition, so going to another page with different audio and clicking play will play the same audio file as the first page unless of course I manually refresh the browser. Is there any way around this?

  • Paul Tomblin
    Paul Tomblin over 15 years
    What advantage does Time::Local give you that the more common POSIX(strftime) doesn't?
  • Leon Timmermans
    Leon Timmermans over 15 years
    That is the kind of thing that either should be a shell script, or it should be made to use a proper Perl module to do the work IMHO.
  • Leon Timmermans
    Leon Timmermans over 15 years
    strftime is for outputting time, timelocal is to 'input' them.
  • Aristotle Pagaltzis
    Aristotle Pagaltzis over 15 years
    No, please don’t. Date::Manip’s own documentation has a big section that tries to convince you not to use it.
  • raldi
    raldi over 15 years
    Why rewrite it as a shell script? It works just fine as-is and I find it extremely useful on a daily basis.
  • Alfredo Hu
    Alfredo Hu over 15 years
    It's always better to use a library function to do a common operation than to roll your own (buggy) solution.
  • Jason Yost
    Jason Yost about 12 years
    I did see the problem on the desktop browser as well. I went with your suggestion of deleting and recreating the audio tag through the DOM.
  • Kevin
    Kevin almost 12 years
    Date::Manip will betray you when you are most vulnerable. Use DateTime. :)
  • Julian Fondren
    Julian Fondren almost 11 years
    @AristotlePagaltzis, where "tries to convince you not to use it" means only "says that it can do everything with one Calendar, but allows that multiple less-than-everythings can be performed more efficiently by multiple other modules." So, everything scottc already said, with more emphasis on Date::Manip being a one-stop solution.
  • kkoolpatz
    kkoolpatz over 8 years
    Not a perl solution if it relies on system date command. Does not work in unix or windows.
  • Thomas Guyot-Sionnest
    Thomas Guyot-Sionnest over 8 years
    epoch time is already in GMT, there' no timezone. By explicitly setting TZ=GMT, aren't you parsing the time as being from the GMT timezone rather than local date/time? (and I think you should rather use TZ=UTC, GMT is a country's timezone)
  • ysth
    ysth over 8 years
    @ThomasGuyot-Sionnest my intent was to illustrate that mktime converts from local time to epoch seconds, so you need to know what local time your input is in and set TZ accordingly (or just assume TZ is already set to what you want, but that's sloppy)
  • Thomas Guyot-Sionnest
    Thomas Guyot-Sionnest over 8 years
    I think it's safe to assume most people will want to use local time and that is what is set on the computer/server. I do understand the zone is important when working with different regions but I think showing an example setting TZ to GMT distracts from the actual answer and may even misled rookies into using the wrong timezone for time input. OTOH you get bonus point for calling tzset() after changing TZ ;)
  • Adam Katz
    Adam Katz about 8 years
    Why use perl when you can use the infinitely more flexible GNU date? date -d "STRING" +%s allows nearly anything, from "yesterday" to "90 days" [after right now] to more traditional things like "Mar 15 2016" and can output into nearly any format as well (+%s is epoch, see date --help for tons more). (It's too bad perl DateTime doesn't have this functionality.)
  • Shantesh
    Shantesh over 7 years
    @scottc it does not work for $string = '18-Sep-2008 12:09:16 PM'; how do i convert to PM to 24 hour format
  • Grant Bowman
    Grant Bowman over 6 years
    $month-1 for zero indexed month !!!!!! I'll try not to forget that again.
  • Spear
    Spear about 6 years
    The 'timelocal' solution below is better since DateTime is not part of a standard Perl installation
  • Michael Goldshteyn
    Michael Goldshteyn about 3 years
    Don't use braces to surround reg-exes that contain braces!