Repository: codeigniter4/CodeIgniter4 (PHP)

Issue:
Bug: Timer::getElapsedTime() returns incorrect value
### PHP Version

8.1

### CodeIgniter4 Version

latest

### CodeIgniter4 Installation Method

Git

### Which operating systems have you tested for this bug?

Linux

### Which server did you use?

apache

### Database

_No response_

### What happened?

There is a bug in `system/Debug/Timer.php`'s `getElapsedTime` function when elapsed times are `>= 1,000` seconds.

(This bug has been in CI since the 3.0 days, in Benchmark.php's elapsed_time function.)

The code is currently:
```php
return (float) number_format($timer['end'] - $timer['start'], $decimals);
```

note that:
```php
$number = (float) number_format(1000 - 1, 4); // returns 999
$number = (float) number_format(1001 - 1, 4); // returns ... 1
```

This is because of the default thousands separator of number_format. To fix, use no thousands separator:
```php
$number = (float) number_format(1001 - 1, 4, '.', '');
```

which returns the expected 1000.0000

However, even without the cast to (float), if the return value is compared to an integer:

```php
if($elapsed_time <= 300) ...
```

this code will trigger, as 1,000.0000 <= 300 . No matter of casting that I have tried will fix this.

### Steps to Reproduce

Call timer start() , then 1,0001 seconds later, call timer stop(). Compare the return value of getElapsedTime to say 5. It will be < 5

### Expected Output

getElapsedTime should not return numbers decorated with a thousands separator, as it messes with comparisons against other integers.

### Anything else?

_No response_


Discussion:
Thank you for reporting.

The return type is `float|null`:
https://github.com/codeigniter4/CodeIgniter4/blob/6198639953139a47b0917a39cd6b401f02d9082c/system/Debug/Timer.php#L81
So `,` should not be included.

I sent a PR  #5798



Patch:
diff --git a/system/Debug/Timer.php b/system/Debug/Timer.php
index 5783c77aae72..9ca51d1c9b08 100644
--- a/system/Debug/Timer.php
+++ b/system/Debug/Timer.php
@@ -78,7 +78,7 @@ public function stop(string $name)
      * @param string $name     The name of the timer.
      * @param int    $decimals Number of decimal places.
      *
-     * @return float|null Returns null if timer exists by that name.
+     * @return float|null Returns null if timer does not exist by that name.
      *                    Returns a float representing the number of
      *                    seconds elapsed while that timer was running.
      */
@@ -96,7 +96,7 @@ public function getElapsedTime(string $name, int $decimals = 4)
             $timer['end'] = microtime(true);
         }
 
-        return (float) number_format($timer['end'] - $timer['start'], $decimals);
+        return (float) number_format($timer['end'] - $timer['start'], $decimals, '.', '');
     }
 
     /**


Test patch:
diff --git a/tests/system/Debug/TimerTest.php b/tests/system/Debug/TimerTest.php
index 7b7b75199ea9..fdd09829d9ff 100644
--- a/tests/system/Debug/TimerTest.php
+++ b/tests/system/Debug/TimerTest.php
@@ -92,8 +92,8 @@ public function testThrowsExceptionStoppingNonTimer()
     public function testLongExecutionTime()
     {
         $timer = new Timer();
-        $timer->start('longjohn', strtotime('-11 minutes'));
-        $this->assertCloseEnough(11 * 60, $timer->getElapsedTime('longjohn'));
+        $timer->start('longjohn', strtotime('-110 minutes'));
+        $this->assertCloseEnough(110 * 60, $timer->getElapsedTime('longjohn'));
     }
 
     public function testLongExecutionTimeThroughCommonFunc()