http://qs1969.pair.com?node_id=597542

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

Consider if I have a date like 31-JAN-2007. How do I convert it to epoch seconds without using Date::Manip or Time::Piece

Replies are listed 'Best First'.
Re: epoch time
by ikegami (Patriarch) on Jan 31, 2007 at 15:19 UTC

    A regexp, a lookup table and (core module) Time::Local.

    use Time::Local qw( timelocal ); my %month_num_by_name = ( JAN => 1, FEB => 2, ... ); my ($d, $m, $y) = split(/-/, $date); $m = $month_num_by_name{$m}; my $time = timelocal(0, 0, 0, $d, $m-1, $y);

    Update: Added code.

      I think timelocal() wants the year to be years since 1900 so code shoud perhaps be

      my $time = timelocal(0, 0, 0, $d, $m-1, $y - 1900);

      Also, for this particular application, why not set the hash up with the subtraction by one already done?

      my %month_num_by_name = ( JAN => 0, FEB => 1, ... );

      Cheers,

      JohnGG

      Update: davorg and ikegami have pointed out that timelocal() does accept dates like 2007 without first subtracting 1900, although it does the right thing if you do the subtraction as well. ikegami also explained his excellent reason for doing the month the way he does.

        I think timelocal() wants the year to be years since 1900

        That would make sense. But the documentation says:

        Strictly speaking, the year should also be specified in a form consistent with localtime(), i.e. the offset from 1900. In order to make the interpretation of the year easier for humans, however, who are more accustomed to seeing years as two-digit or four-digit values, the following conventions are followed:

        • Years greater than 999 are interpreted as being the actual year, rather than the offset from 1900. Thus, 1964 would indicate the year Martin Luther King won the Nobel prize, not the year 3864.

        • Years in the range 100..999 are interpreted as offset from 1900, so that 112 indicates 2012. This rule also applies to years less than zero (but see note below regarding date range).

        • Years in the range 0..99 are interpreted as shorthand for years in the rolling "current century," defined as 50 years on either side of the current year. Thus, today, in 1999, 0 would refer to 2000, and 45 to 2045, but 55 would refer to 1955. Twenty years from now, 55 would instead refer to 2055. This is messy, but matches the way people currently think about two digit dates. Whenever possible, use an absolute four digit year instead.

        The scheme above allows interpretation of a wide range of dates, particularly if 4-digit years are used.

        I think timelocal() wants the year to be years since 1900

        It accepts both.

        why not set the hash up with the subtraction by one already done?

        I like $m having a natural value like $d (1..~31) and $y (19xx) do. I always follow localtime and gmtime with $m++; $y += 1900;, and I always specify $m-1 for timelocal and timegm. Not seeing $m-1 raises alarms in my head.

Re: epoch time
by jbert (Priest) on Jan 31, 2007 at 17:36 UTC
    The first rule of coding club is: "never implement your own date/time/timezone handling code".

    The above advice about Time::Local is good, but if it weren't, your best option would be to effectively copy the code you need from one of the modules you listed.

    If you were to consider doing it yourself, don't forget to think about whether you need to take account of: timezones (numeric), timezones (named), leap years, leap seconds, daylight savings time (in all the different timezones, changing over the years) and how comprehensive your test suite needs to be. I think timezones possibly also move on a scale of decades.

    Also don't forget to think about whether someone else will be calling your code for similar purposes but who does need to worry about such things.

    (The second rule of coding club is "never implement your own character escaping/unicode/charset conversion code").

      The third rule is "don't write your own HTML parsing or templating code"

      The fourth rule is "don't write your own XML parsing code".

        Don't forget, "don't write your own encryption/hashing code"
Re: epoch time
by spatterson (Pilgrim) on Jan 31, 2007 at 15:22 UTC
    Why can't you use those modules? There's also Date::Calc and Date::PCalc, doing this by hand would be ... painful, but you could have a hash of month lengths keyed by name, then subtract 1970 from the year and total up the days in each month before this one.

    If there is no code here, it is for your enlightenment
      Don't forget leap years...
        and that (among other things) is why its wiser to use established modules when you can.

        just another cpan module author
Re: epoch time
by logie17 (Friar) on Jan 31, 2007 at 16:22 UTC
    Use Time::Local. For example:
    #! /usr/local/bin/perl use Time::Local; my $timestring = timelocal(0,0,0,31,0,2007); print $timestring,"\n";

    Outputs:
    1170230400

    Thanks,

    s;;5776?12321=10609$d=9409:12100$xx;;s;(\d*);push @_,$1;eg;map{print chr(sqrt($_))."\n"} @_;
Re: epoch time
by Corion (Patriarch) on Jan 31, 2007 at 15:21 UTC

    If you have Time::Piece, just use its strptime function to parse a time string and return a Time::Piece object.

    Update: I missed the "without" in your query. If you don't want to use Time::Piece, go with ikegami's advice or install DateTime and DateTime::Format::Strptime.

Re: epoch time
by klekker (Pilgrim) on Jan 31, 2007 at 18:05 UTC
    On my linux system
    $ date --date=31-JAN-2007 Wed Jan 31 00:00:00 CET 2007

    And converted:
    $ date --date=31-JAN-2007 +%s 1170198000
    (If you mean seconds since `00:00:00 1970-01-01 UTC' with "epoch seconds" and don't mind using backticks.)
Re: epoch time
by tubaandy (Deacon) on Jan 31, 2007 at 19:39 UTC
    Out of curiosity, is there a reason to not use these modules? I have found Date::Manip to be exceedingly helpful. (OK, it's for a script that reminds people that it's their turn to bring bagels and coffee into the office. You'd be surprised how irritated folks get when they don't show up on time.)

    tubaandy
      Hi,

      Really it was very useful. Have a method in Date::Manip ie; $date = Date_NextWorkDay($date,$off ,$time); very useful. Its easy.

      But had a problem here. Consider if I am adding 10 to a date that falls on saturday or sunday then the next working day must be similar to that when I add 10 working days with a date that falls on Friday.

      But it doesnt happens like that with Date::Manip

      I am not sure whether I have some mistake in understanding. But anyway fixed the problem by checing whether is a working day if yes then add 10 else add 9

      Thanks
Re: epoch time
by peters (Sexton) on Feb 01, 2007 at 21:16 UTC
    Uh, there's always Date::Parse:
    str2time("31-JAN-2007");
    Peter Scott
    Perl Medic