Compared to Datetime class, is the date function more performative?

Asked

Viewed 299 times

7

It is very common to read some tutorials or articles saying that programming Object Oriented can cost more (I speak in relation to memory).

Since I started programming, there’s that little itch in my mind, saying, "Using an object is heavier than using a function".

An example that I sometimes wonder is if it is really necessary to use the class DateTime when you already have date.

For example:

echo new (DateTime('+3 days'))->format('d/m/Y');

echo date('d/m/Y', strtotime('+3 days'));

Taking into account PHP object-oriented programming in relation to procedural, it is correct to state that date is more performatic than DateTime? I should really worry about that?

  • 4

    If you do not have a clear reason to worry about performance (based on a performance test for example), avoiding the object will be considered a microtimization and therefore superfluous and prone to worsening the readability of the code. If using the object brings you benefits, prefer the object.

  • 1

    Just as if the object does not bring any benefit, do not use it :) Not even by performance, if it were the case that the object is faster, which is not.

  • @Wallacemaxters "Using object is heavier than using function" take it out of your hair, use design patterns, use code coherence, in the example cited to classe DateTime has numerous advantages over date and honestly any and every answer will not convince that one is better than the other, exhaustion test only brings conceptual damage mainly with this aspect, I guarantee if it will not instilling 10000 classes Datetime. Just a developer positioning that has been using this for a long time ...

2 answers

4

Using a 512 RAM VM and 1 (one) processing core (i7), Debian 8 64bits, Apache 2.4 and PHP 5.6, I ran the following test, considering the same implementation used in the question:

Using Datetime::createFromFormat

for($i = 0; $i < 100000; $i++){
    $tmp = DateTime::createFromFormat('U', strtotime('+3 days'))->format('Y-m-d H:i:s');
}

Upshot:

Time: 3.509903 s

And also using date:

for($i = 0; $i < 100000; $i++){
    $tmp = date('Y-m-d H:i:s', strtotime('+3 days'));
}

Upshot:

Time: 1.755909 s

So it seems that date is faster than DateTime::createFromFormat.

With the implementation using Datetime has the createFromFormat, I decided to simplify the code further so that the comparison is more coherent.

Simplifying the request and increasing the requests:

Calling date 1,000,000 times:

for($i = 0; $i < 1000000; $i++){
    $tmp = date('Y-m-d h:i:s');
}

Time: 7.605172 s

Calling New DateTime 1,000,000 times:

for($i = 0; $i < 1000000; $i++){
    $tmp = (new DateTime())->format('Y-m-d h:i:s');
}

Time: 12.230210 s

Time calculation:

Time was calculated taking the initial and final time with getTime(); then calculating:

$execTime = $finalTime - $time; 
echo number_format($execTime, 6) . ' s';

Of course the runtime will vary from environment to environment, but what is being taken into account here is what is the best performance between the two implementations.

Thus, it can be concluded that the implementation using date is faster than using the class DateTime

Remembering that speed is not everything. The use of each will depend on each situation.

  • 1

    How you counted the time of the result?

  • Taking start and end time with getTime(); then calculating: $execTime = $finalTime - $time; echo number_format($execTime, 6) . s';

  • @Viniciusmaia I was going to ask the same. Also it was good to know what the settings of your system.

  • @Viniciusmaia, VM with 512 RAM and 1 (one) processing core (i7), Debian 8 64bits, Apache 2.4, PHP 5.6.

  • 1

    In the answer I posted I quoted your name and the tests of your answer. A key point that I find mistaken in your test with DateTime is misuse. Obviously using it inappropriately and, worse than that, without actually using class resources, will bring bad results. Example, you are creating the instances multiple times with each iteration. You only need one instance. And also the fact of using strtotime('+3 days') which increases time consumption and is not even part of the class. If it is to test, use the class resources. I demonstrated this in my reply.

  • 1

    Good observation, Daniel. That really makes a big difference. He could use the new Datetime only once and then, inside the loop, use the ->Modify ("+1 day")

  • @Viniciusmaia: the purpose of the answer was to test the performance between one method and another... was not to write the code in the most efficient way.

  • The purpose is clear, Allan. The problem is that it became vague by inducing something wrong because in the real world it is not used that way. An object serves to reuse processes. In this case it is practically killing the object, using it as a procedural function.

  • Allan @Danielomine is right, on top of everything AP even talks about object-oriented programming and in this case your answer is a bit misleading, which is not used like this in OO.

  • you should also say in your answer how you calculate execution times.

  • @Jorgeb., this afternoon I will review and improve this response.

Show 6 more comments

3

It is obvious that a resource that consumes more memory will always be more expensive.

The more code, even if it is a comma more, it consumes more memory.

Example:

Teste1

<?php

//

Teste2

<?php


//

Teste2 consumes more resources simply by having an extra line break. Of course, we’re not considering caching here.

Based on this, imagine the comparison between a function and a class. A class requires a little more memory, requires instantiation of the object, etc. A function only receives the parameters and returns the result procedural.

Also note how the environment and the way you use resources greatly influence performance. Let’s take the example of the @Allanandrade response

Datetime

for($i = 0; $i < 100000; $i++){
    $tmp = DateTime::createFromFormat('U', strtotime('+3 days'))->format('Y-m-d H:i:s');
}
/*
tempo: 0.76813006401062 (segundos)
pico memória: 435824 bytes
memória final: 399816 bytes
*/

date()

for($i = 0; $i < 100000; $i++){
    $tmp = date('Y-m-d H:i:s', strtotime('+3 days'));
}
/*
tempo: 0.31057095527649 (segundos)
pico memória: 435328 bytes
memória final: 399296 bytes
*/

Note that the cost of memory doesn’t even change with 1 million runs. Obviously the class has a cache engine or internal optimization. Otherwise the memory cost would be much higher.

Time is also "light years" from Allan’s response test. Since he didn’t post how he did the tests, what environment, etc., I can’t compare it to his results. It may also have confused the time of micro, Mili or seconds. If it can make it clearer, we can have a more accurate comparison.

Now we will use it in a "smart" way, because we are dealing with an object and it makes no sense to instantiate it multiple times for a single purpose. In this case we cannot blame the language, the environment or tools. It is the programmer’s fault.

Here we create the instance and set the interval outside the loop of repetition. For this is the obvious to do. In the first test, despite the use of Datetime, is incoherently using strtotime(). The right thing would be to use the class’s own resources. For clarification, I will use the function date_interval_create_from_date_string() which is the procedural version of DateInterval::createFromDateString(). Actually, it’s an alias.

$date = new DateTime('2016-08-30');
$interval = date_interval_create_from_date_string('3 days');

for($i = 0; $i < 100000; $i++){
    $tmp = $date->add($interval)->format('Y-m-d');
}
/*
tempo: 0.18332006645203 (segundos)
pico memória: 436384 bytes
memória final: 400856 bytes
*/

Note that now the "game turned" to a difference that we can consider "brutal". Almost half the time compared to the test using the function date().

To avoid being unfair, let’s optimize the procedural style

$interval = strtotime('+3 days');
for($i = 0; $i < 100000; $i++){
    $tmp = date('Y-m-d H:i:s', $interval);
}
/*
tempo: 0.15265989303589 (segundos)
pico memória: 435376 bytes
memória final: 399344 bytes
*/

Point to the procedural style!!

Still, considering an unusual situation that is run 1 million times, the difference is very small. Only 0.03 microseconds.

If we apply use of optimizers such as opcache, among others, the difference can fall to zero or even change sides because the latest features have features that allow for better optimization. Old functions, usually not.

Wait! There’s more!

A little change, using something more appropriate:

$date = new DateTime('2016-08-30');
$interval = new DateInterval('P3D');

for($i = 0; $i < 100000; $i++){
    $tmp = $date->add($interval);
}
/*
tempo: 0.1128888130188 (segundos)
pico memória: 435824 bytes
memória final: 400040 bytes
*/

The game turned again to Datetime class.

A difference of 0.04 seconds faster compared to the best performance in function use date() so far.

Regarding the cost of memory, obviously it will not change, because the class has a larger amount of codes. However, it is an irrelevant cost. The most relevant thing here, within this test context, is the speed.

In a general summary, performance depends on a set of factors. Most are purely logical and common sense in the use of tools.

We may think that all of these are micro-timizations, but as we can see, depending on how it is done and summed up with other optimized routines, all together, make a significant difference.

Considerations

One has to consider the context under which conditions the X or Y resource will be used. Sometimes a simple date() Formatting anything is more convenient. Other times you need something a little more complex where the use of procedural functions complicate. At this point comes common sense to know how to discern what is most appropriate. Keep in mind the kiss principle (Keep it simple, stupid).

Because they were written at the beginning of the creation of PHP, the old functions do not have adequate standards compared to more modern languages. For this, PHP has been gradually deploying features like the class DateTime which is already present in the language since 2004 but, some programmers, due to the dissemination of disinformation, simply unaware or ignore. The 12-year time does not seem like much, but in the computer world is the equivalent of 1 century in human life.
IT evolves very fast, and if we get caught up in methods, customs and actions, we lose the thread and get stuck in an outdated and often ignorant conception.

I can show more examples of how to further optimize both styles above, including using optimizers and cache, but I believe the above examples and explanations have made it clear.

How the tests were performed?

An important point is, all this ran under Windows and PHP as Apache module.

Also try running a well-configured Linux environment with PHP-FPM under Nginx. Finally, test in different environments. It is well known that PHP as a module is less performative than as CGI or these new media like PHP-FPM.

Important to know that the benchmark was made using only PHP itself to simulate a real web environment to the fullest.

The memory cost may be lower considering only the execution of the proposed scripts. The end result of memory costs includes a small bootstrap and the loading of 2 simple libraries for running time and memory calculation.

The complete script:

<?php
date_default_timezone_set('Asia/Tokyo');

ini_set('error_reporting', E_ALL & ~E_STRICT & ~E_DEPRECATED); // & ~E_NOTICE
ini_set('log_errors', true);
ini_set('html_errors', false);
ini_set('display_errors', true);

define('CHARSET', 'UTF-8');

ini_set('default_charset', CHARSET);
mb_http_output(CHARSET);
mb_internal_encoding(CHARSET);

header('Content-Type: text/html; charset='.CHARSET);

include 'Bench.php';
include 'Memory.php';

use \Tipui\Libs\Bench as Bench;
use \Tipui\Libs\Memory as Memory;

Bench::Start();

// Aqui coloca o script que deseja testar.

$bench = Bench::Calc();
$memory = Memory::GetData();
echo '<pre>';
print_r($bench);
print_r($memory);
echo '</pre>';

Bench.php

<?php
namespace Tipui\Libs;

class Bench
{

    protected static $ini;

    public static function Start($id = 0)
    {
        /*
        Get the start time in microseconds, as a float value
        */
        self::$ini[$id] = microtime(true);
    }

    public static function Calc($id = 0)
    {
        /*
        Get the difference between the start and the end time in microseconds, as a float value
        */
        $end = microtime(true);
        $diff = $end - self::$ini[$id];

        /*
        Break the difference into seconds and microseconds
        */
        return array($diff - intval($diff), self::$ini[$id], $end);
    }

}

Memory php.

<?php
namespace Tipui\Libs;

class Memory
{

    private static $data;

    public static function GetData($id = 0)
    {
        /*
        Get the start time in microseconds, as a float value
        */
        self::$data[$id]['peak'] = memory_get_peak_usage();
        self::$data[$id]['current_usage'] = memory_get_usage();
        return self::$data[$id];
    }

    public static function Usage($id = 0)
    {
        /*
        Get the start time in microseconds, as a float value
        */
        return self::$data[$id]['usage'] = memory_get_usage();
    }

}

Ambience

SO: Windows 10 pro 64bit
RAM: 2 X 8GB (DDR3)
CPU: Intel i7-4770K @ 3.50GHz
PHP 7.0.5 (módulo)
Apache 2.4.20

(Hardware in default manufacturer setagens. Windows, Apache and PHP also in default settings.)

  • I am here testing with Ubuntu Server 14.04, 8G RAM, i7-3770 @ 3.4GHz, PHP 5.5.9 and apache 2.4.7 and I am not having results even similar to yours, there is a big difference from one use to the other.

  • By the way, I have now done the test with 1 million and, despite waiting for the result, the result is 0.28077387809753, smaller than it appeared to me with 100 thousand. You have an explanation?

  • For 1 million iterations, as it will obviously pass 1 second, modify the output of the method Calc() in class Bench. Place return array($diff, $diff - intval($diff), self::$ini[$id], $end);. Your result will probably be 4.28 seconds.

  • Still, me with a hundred thousand and with the answer from Lacobus I have times on the basis of seconds. Your times of 0.2 micro seconds are at least unreal. Something is wrong there.

  • the time is that same in seconds 0.111..... micro seconds no..

  • sorry, now that I noticed the comments in the codes is "microseconds"... it was supposed to be "seconds". I copied the structure of other tests where I calculated microseconds and I didn’t pay attention. But this is somewhat irrelevant. The important thing is the difference between class datetime and function date(). That the "myth" in these tests and how the tests in the other answers are poorly done.

Show 1 more comment

Browser other questions tagged

You are not signed in. Login or sign up in order to post.