Skip to content

Commit

Permalink
Avoid warnings on ComputesNanosecondTimestamps (#21)
Browse files Browse the repository at this point in the history
* Avoid warnings on ComputesNanosecondTimestamps

* Tweaks

- Compute `strlen` once.
- `microtime(true)` can return different number of decimals:

These are all valid:

```
1706498205.1234
1706498205.123
1706498205.12
1706498205.1
```

* Refactor and tests

* Improve float length and more tests
  • Loading branch information
fedeisas authored Feb 7, 2024
1 parent 4e5b02d commit 6e64912
Show file tree
Hide file tree
Showing 2 changed files with 117 additions and 19 deletions.
59 changes: 44 additions & 15 deletions src/Traits/ComputesNanosecondTimestamps.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

trait ComputesNanosecondTimestamps
{
protected const TO_NANO = 1000000000;

/**
* A public way tog et the nanosecond precision we desire.
*
Expand All @@ -14,25 +16,52 @@ trait ComputesNanosecondTimestamps
public function getNanoSecondTimestamp($timestamp = null)
{
if ($timestamp instanceof \DateTime) {
return $timestamp->getTimestamp() * 1000000000;
}
return $timestamp->getTimestamp() * self::TO_NANO;
} elseif (is_int($timestamp)) {
$length = strlen((string) $timestamp);

if (strlen($timestamp) == 19) {
// Looks like it is already nanosecond precise!
return $timestamp;
}
return match ($length) {
// Looks like it is already nanosecond precise!
19 => $timestamp,
// This appears to be in seconds
10 => $timestamp * self::TO_NANO,
default => $this->generateTimestamp(),
};
} elseif (is_string($timestamp)) {
if (preg_match("/\d{10}\.\d{1,4}$/", $timestamp)) {
return (int) ($timestamp * self::TO_NANO);
} elseif (ctype_digit($timestamp)) {
$length = strlen($timestamp);

if (strlen($timestamp) == 10) {
// This appears to be in seconds
return $timestamp * 1000000000;
}
return match ($length) {
// Looks like it is already nanosecond precise!
19 => (int) $timestamp,
// This appears to be in seconds
10 => (int) ($timestamp * self::TO_NANO),
default => $this->generateTimestamp(),
};
}
} elseif (is_float($timestamp)) {
$integerLength = (int) floor(log10(abs($timestamp))) + 1;

if (preg_match("/\d{10}\.\d{4}/", $timestamp)) {
// This looks like a microtime float
return (int)($timestamp * 1000000000);
return match ($integerLength) {
// Looks like it is already nanosecond precise!
19 => (int) $timestamp,
// This appears to be in seconds
10 => (int) ($timestamp * self::TO_NANO),
default => $this->generateTimestamp(),
};
}

// We weren't given a valid timestamp, generate.
return (int)(microtime(true) * 1000000000);
return $this->generateTimestamp();
}

/**
* @return int
*/
protected function generateTimestamp(): int
{
return (int) (microtime(true) * self::TO_NANO);
}
}
}
77 changes: 73 additions & 4 deletions tests/InfluxDBV2DriverTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,84 @@ public function testTcpWriteClient()
);
}

public function testNanoSecondTimestamp()
/**
* @dataProvider nanoSecondTimestampInvalid
*/
public function testNanoSecondTimestampInvalid($input)
{
$this->setupInfluxDB();

$influx = app(InfluxDB::class);

$this->assertEquals(1508713728000000000, $influx->getNanoSecondTimestamp(1508713728000000000));
$this->assertEquals(1508713728000000000, $influx->getNanoSecondTimestamp(1508713728));
$this->assertEquals(1508713728000000000, $influx->getNanoSecondTimestamp(new \DateTime('@1508713728')));
$now = $influx->getNanoSecondTimestamp();
$result = $influx->getNanoSecondTimestamp($input);

$this->assertTrue(is_int($result));
$this->assertEquals(19, strlen((string) $result));
$this->assertGreaterThanOrEqual($now, $result);
}

/**
* @dataProvider nanoSecondTimestampValid
*/
public function testNanoSecondTimestamp($expected, $input)
{
$this->setupInfluxDB();

$influx = app(InfluxDB::class);

$result = $influx->getNanoSecondTimestamp($input);

$this->assertTrue(is_int($result));
$this->assertEquals(19, strlen((string) $result));
$this->assertEquals($expected, $result);
}

public static function nanoSecondTimestampValid()
{
$expected = 1508713728000000000;
$expectedPrecise = 1508713728123400000;

return [
[$expected, 1508713728000000000,],
[$expected, 1508713728,],
[$expected, '1508713728000000000',],
[$expected, '1508713728',],
[$expected, new \DateTime('@1508713728'),],
[$expected, '1508713728.0000',],
[$expected, '1508713728.000',],
[$expected, '1508713728.00',],
[$expected, '1508713728.0',],
[$expected, 1508713728.0000,],
[$expected, 1508713728.000,],
[$expected, 1508713728.00,],
[$expected, 1508713728.0,],
[$expectedPrecise, 1508713728123400000,],
[$expectedPrecise, '1508713728123400000',],
// [$expectedPrecise, '1508713728.1234',], // PHP float precision breaks this
// [1508713728123000000, '1508713728.123',], // PHP float precision breaks this
[1508713728120000000, '1508713728.12',],
[1508713728100000000, '1508713728.1',],
// [1508713728123400000, 1508713728.1234,], // PHP float precision breaks this
// [1508713728123000000, 1508713728.123,], // PHP float precision breaks this
[1508713728120000000, 1508713728.12,],
[1508713728100000000, 1508713728.1,],
];
}

public static function nanoSecondTimestampInvalid()
{
return [
['abc'], // letters
['150871372800000000a',], // numbers with letters
[150871372800000000,], // 18 digits
[15087137281,], // 11 digits
[150871372,], // 9 digits
[15087137,], // 8 digits
[0,],
[0.0,],
['000000000.1',],
['000000000.0',],
];
}
}

0 comments on commit 6e64912

Please sign in to comment.