Beefy Boxes and Bandwidth Generously Provided by pair Networks
"be consistent"
 
PerlMonks  

Re: High-speed Date Formatting

by BrowserUk (Patriarch)
on Jul 12, 2013 at 00:23 UTC ( [id://1043841]=note: print w/replies, xml ) Need Help??


in reply to *SOLVED* High-speed Date Formatting

If can live with its limitations(1), you could try something like this:

#! perl -slw use strict; use constant MONTHS => { qw[ Jan 0 Feb 31 Mar 59 Apr 90 May 120 Jun 151 Jul 181 Aug 212 Sep 242 Oct 272 Nov 303 Dec 334 ] }; sub str2epoch { my( $d, $m, $y, $H, $M, $S ) = $_[0] =~ m[^.... (\d\d) (...) (\d\d\d\d) (\d\d):(\d\d):(\d\d)] or die "Bad format $_[0]"; my $leaps = int( ($y - 1970) / 4 + 0.5 ); (((($y-1970)*365 +$leaps+MONTHS->{$m}+($d-1))*24 +$H)*60 +$M)*60 + +$S; } my $date = 'Fri, 01 Mar 2013 01:21:14 +0000';; print str2epoch( $date ); print scalar localtime str2epoch( $date ); print scalar localtime str2epoch( 'Fri, 12 Jul 2013 01:20:34' );; __END__ C:\test\primes>..\str2epoch.pl 1362100874 Fri Mar 1 01:21:14 2013 Fri Jul 12 02:20:34 2013

And if you need a little more you might parse the numbers with unpack instead of the regex engine.

1 Limitations include:

  • No leap seconds;
  • No daylight savings;
  • No timezones;
  • Only works for another 87 years.

With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.

Replies are listed 'Best First'.
Re^2: High-speed Date Formatting
by rjt (Curate) on Jul 12, 2013 at 00:54 UTC
    No timezones;

    This much is (sort of) trivial to fix. Add  ([+-]\d{4}) to the end of your regex, and then include - $tz/100*3600 - $tz%100*60 at the end of the expression.

    sub str2epoch { my( $d, $m, $y, $H, $M, $S, $tz ) = $_[0] =~ m/^.... (\d\d) (...) (\d\d\d\d) (\d\d):(\d\d):(\d\d) ([+-]\d{4 +})/ or die "Bad format $_[0]"; my $leaps = int( ($y - 1970) / 4 + 0.5 ); (((($y-1970)*365 +$leaps+MONTHS->{$m}+($d-1))*24 +$H)*60 +$M)*60 + +$S - ($tz < 0 ? -1 : 1)*(substr($tz,1,2)*3600 + substr($tz, +3)*60); }
    • No leap seconds;
    • No daylight savings;
    • Only works for another 87 years.

    See my answer for timegm, which does slow things down, but is a bit more robust. ++ for pure-Perl that out-performs the "efficient" Time::Local routines and works in most all cases, though!

    Edit: Updated $tz calc for fractional hours.

      No timezones; This much is trivial to fix....

      Indeed, that is sufficiently efficient to make it silly not to include it. Thank you.

      Though It seems silly not to let the regex do its work. I reformulated that as:

      sub str2epoch { my( $d, $m, $y, $H, $M, $S, $tzs, $tzh, $tzm ) = $_[0] =~ m[^.... (\d\d) (...) (\d\d\d\d) (\d\d):(\d\d):(\d\d) ([+-])(\d +\d)(\d\d)] or die "Bad format $_[0]"; my $leaps = int( ($y - 1970) / 4 + 0.5 ); (((($y-1970)*365 +$leaps+MONTHS->{$m}+($d-1))*24 +$H)*60 +$M)*60 + +$S - ($tzs eq '-' ? -1 : 1)*$tzh*3600 + $tzm*60; }
      See my answer for timegm, which does slow things down, but is a bit more robust

      All the others can be handled, but eventually you just end up with the morass that is DateTime which I have no time for :)

      (There is a simple workaround for the 2100 problem, but it wouldn't come to mind as I write that. And the last version I wrote is archived on a CD somewhere.)


      With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
      Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
      "Science is about questioning the status quo. Questioning authority".
      In the absence of evidence, opinion is indistinguishable from prejudice.
Re^2: High-speed Date Formatting
by hdb (Monsignor) on Jul 12, 2013 at 08:58 UTC

    Another small speed up can be achieved by replacing

    my $leaps = int( ($y - 1970) / 4 + 0.5 ); (((($y-1970)*365 +$leaps+MONTHS->{$m}+($d-1))*24 +$H)*60 +$M)*60 + +$S;

    with

    (((int(($y-1970)*365.25-.5)+MONTHS->{$m}+$d)*24 +$H)*60 +$M)*60 +$S;

    in my experiments between 5 to 10%. All other attempts using split and unpack are much slower. I found substr to be very fast:

    sub str2epoch3 { (((int((substr($_[0],12,4)-1970)*365.25-.5)+ MONTHS->{substr($_[0],8,3)}+substr($_[0],5,2))*24 +substr($_[0],1 +7,2))*60 + substr($_[0],20,2))*60 +substr($_[0],23,2); }

    about 60% faster than BrowserUk's code. I wonder whether there is something wrong...

    Here is my full code:
Re^2: High-speed Date Formatting
by sundialsvc4 (Abbot) on Jul 12, 2013 at 02:59 UTC

    Only works for another 87 years.

    This reminds me of a comment that I actually found in some source-code once:   “dig me up and I’ll fix it then.”

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://1043841]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others having a coffee break in the Monastery: (4)
As of 2024-04-25 22:32 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found