update: timezone offset calc and date formatting

  • Thread starter Leendert Bottelberghs
  • Start date
L

Leendert Bottelberghs

Hi all,

a few days ago I posted on this list about timezone offset calculations.
After some suggestions, I both tested with the use of some Date modules,
as rewrote my own routine for calcutating the time offset and formatting a
date-time string. Benchmark tests show that my own routine is about 8000%
(!!!) faster than using the Date::Manip module. This is especially
interesting when you have to format dates at a high rate, such as for
http-logging. I'll elaborate some more on my findings in this post.

I need a formatted date-time string for a mod_perl module that writes
access logs. Apache uses it's own date format, which includes the timezone
offset. As a log entry is written for every request, and thus the date
format has to be calculated for every request, I want it's overhead to be
minimal.

I wanted to test two different modules for date formatting and calcs. I
tried to install the - very complete - module DateTime. But for some
reasons it wouldn't install on my system. Besides the fact that it is very
complete, it also seemed like to be a bit over-the-top for what I needed.
I succeeded in using Date::Manip for constructing the date-format string,
which looks like: [08/Apr/2005:11:24:03 +0100]. The code for constructing
this string is fairly simple and concise:

<code>
sub DateManip {
my $time = &UnixDate("today", "[%d/%b/%Y:%H:%M:%S %z]"); return $time;
}
</code>

Where as my own routine is a bit more complex:

<code>
sub homeBrew {
my @lctime = localtime();
my @gmtime = gmtime();
my $mo = (($lctime[2]-$gmtime[2])%24)*60+($lctime[1]-$gmtime[1])%60;
my $tz = int($mo/60)*100+($mo/abs($mo))*($mo%60);
my $time = sprintf "[%02d/%3s/%4d:%02d:%02d:%02d %+05d]",
($lctime[3],
(qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec)[$lctime[4]]),
(1900+$lctime[5]),
$lctime[2],
$lctime[1],
$lctime[0],
$tz);
return $time;
}
</code>

The main calculations are for the timezone difference. I used Benchmark to
measure the performace of both routines, and here are the results (P4
2GHz):

Benchmark: running DateManip, homeBrew for at least 10 CPU seconds...
DateManip: 10 wallclock secs (10.46 usr + 0.02 sys = 10.48 CPU) @
280.34/s (n=2938)
homeBrew: 11 wallclock secs ( 9.74 usr + 0.32 sys = 10.06 CPU) @
22500.00/s (n=226350)

Rate DateManip homeBrew
DateManip 280/s -- -99% homeBrew 22500/s 7926%
--

I'd say that is quite a difference! Since I want to use this on a
webserver, where a probable 100-300 requests/second arrive, I don't want
my CPU to be fully occupied formatting a date.

The main performance gain is in the algorithm for calculating the timezone
offset. In the previous discussion, "Geoff" pointed out, that timezone
offset is not always in full hours, but can also differ 30 minutes. He
suggested calculating the difference in seconds. So I did, using
Time::Local to convert localtime() and gmtime() to seconds. After
calculating the difference in seconds, I have to convert it back to hours
and minutes in order to get the proper format. This converting was
obviously CPU-consuming, as this routine was approx. 15x slower than the
algorithm used in the current routine. This algorithm works as follows: 1.
calculate hour difference:
a = (localtime(hours) - gmtime(hours))%24
2. convert these hours to minutes:
b = a*60
3. calculate the minute difference:
c = (localtime(minutes) - gmtime(minutes))%60
4. sum to get the total time diff in minutes:
d = b + c
5. prepare to format to 4 digit hhmm number:
e = int(d/60)*100+(d/abs(d))*(d%60)

To demonstrate the efficiency of using this algorithm in stead of the
Date::Manip method, I did another test where I only formatted the
time-zone offset. The routines:

<code>
sub homeBrew {
my @lctime = localtime();
my @gmtime = gmtime();
my $mo = (($lctime[2]-$gmtime[2])%24)*60+($lctime[1]-$gmtime[1])%60;
my $tz = int($mo/60)*100+($mo/abs($mo))*($mo%60);
my $time = sprintf "%+05d", $tz;
return $time;
}
}
sub DateManip {
my $time = &UnixDate("today", "%z");
return $time;
}
</code>

The Benchmark results:

Benchmark: running DateManip, homeBrew for at least 10 CPU seconds...
DateManip: 11 wallclock secs (10.51 usr + 0.02 sys = 10.53 CPU) @
256.13/s (n=2697)
homeBrew: 11 wallclock secs ( 9.85 usr + 0.38 sys = 10.23 CPU) @
28406.06/s (n=290594)

Rate DateManip homeBrew
DateManip 256/s -- -99% homeBrew 28406/s 10991%
--

This shows that my algorithm is about 100x faster than using Date::Manip.
A significant difference I'd say.

Conclusion: if you have to format time in a high load environment, it's
definitely worth it to programm your own algorithms for formatting date
and time. If anyone has an even more efficient algorithm than mine, I'd
like to hear it.


-leendert bottelberghs
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,483
Members
44,901
Latest member
Noble71S45

Latest Threads

Top