Skip to content

Commit 6e64912

Browse files
authored
Avoid warnings on ComputesNanosecondTimestamps (#21)
* 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
1 parent 4e5b02d commit 6e64912

File tree

2 files changed

+117
-19
lines changed

2 files changed

+117
-19
lines changed

src/Traits/ComputesNanosecondTimestamps.php

Lines changed: 44 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
trait ComputesNanosecondTimestamps
66
{
7+
protected const TO_NANO = 1000000000;
8+
79
/**
810
* A public way tog et the nanosecond precision we desire.
911
*
@@ -14,25 +16,52 @@ trait ComputesNanosecondTimestamps
1416
public function getNanoSecondTimestamp($timestamp = null)
1517
{
1618
if ($timestamp instanceof \DateTime) {
17-
return $timestamp->getTimestamp() * 1000000000;
18-
}
19+
return $timestamp->getTimestamp() * self::TO_NANO;
20+
} elseif (is_int($timestamp)) {
21+
$length = strlen((string) $timestamp);
1922

20-
if (strlen($timestamp) == 19) {
21-
// Looks like it is already nanosecond precise!
22-
return $timestamp;
23-
}
23+
return match ($length) {
24+
// Looks like it is already nanosecond precise!
25+
19 => $timestamp,
26+
// This appears to be in seconds
27+
10 => $timestamp * self::TO_NANO,
28+
default => $this->generateTimestamp(),
29+
};
30+
} elseif (is_string($timestamp)) {
31+
if (preg_match("/\d{10}\.\d{1,4}$/", $timestamp)) {
32+
return (int) ($timestamp * self::TO_NANO);
33+
} elseif (ctype_digit($timestamp)) {
34+
$length = strlen($timestamp);
2435

25-
if (strlen($timestamp) == 10) {
26-
// This appears to be in seconds
27-
return $timestamp * 1000000000;
28-
}
36+
return match ($length) {
37+
// Looks like it is already nanosecond precise!
38+
19 => (int) $timestamp,
39+
// This appears to be in seconds
40+
10 => (int) ($timestamp * self::TO_NANO),
41+
default => $this->generateTimestamp(),
42+
};
43+
}
44+
} elseif (is_float($timestamp)) {
45+
$integerLength = (int) floor(log10(abs($timestamp))) + 1;
2946

30-
if (preg_match("/\d{10}\.\d{4}/", $timestamp)) {
31-
// This looks like a microtime float
32-
return (int)($timestamp * 1000000000);
47+
return match ($integerLength) {
48+
// Looks like it is already nanosecond precise!
49+
19 => (int) $timestamp,
50+
// This appears to be in seconds
51+
10 => (int) ($timestamp * self::TO_NANO),
52+
default => $this->generateTimestamp(),
53+
};
3354
}
3455

3556
// We weren't given a valid timestamp, generate.
36-
return (int)(microtime(true) * 1000000000);
57+
return $this->generateTimestamp();
58+
}
59+
60+
/**
61+
* @return int
62+
*/
63+
protected function generateTimestamp(): int
64+
{
65+
return (int) (microtime(true) * self::TO_NANO);
3766
}
38-
}
67+
}

tests/InfluxDBV2DriverTest.php

Lines changed: 73 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,15 +25,84 @@ public function testTcpWriteClient()
2525
);
2626
}
2727

28-
public function testNanoSecondTimestamp()
28+
/**
29+
* @dataProvider nanoSecondTimestampInvalid
30+
*/
31+
public function testNanoSecondTimestampInvalid($input)
2932
{
3033
$this->setupInfluxDB();
3134

3235
$influx = app(InfluxDB::class);
3336

34-
$this->assertEquals(1508713728000000000, $influx->getNanoSecondTimestamp(1508713728000000000));
35-
$this->assertEquals(1508713728000000000, $influx->getNanoSecondTimestamp(1508713728));
36-
$this->assertEquals(1508713728000000000, $influx->getNanoSecondTimestamp(new \DateTime('@1508713728')));
37+
$now = $influx->getNanoSecondTimestamp();
38+
$result = $influx->getNanoSecondTimestamp($input);
39+
40+
$this->assertTrue(is_int($result));
41+
$this->assertEquals(19, strlen((string) $result));
42+
$this->assertGreaterThanOrEqual($now, $result);
3743
}
3844

45+
/**
46+
* @dataProvider nanoSecondTimestampValid
47+
*/
48+
public function testNanoSecondTimestamp($expected, $input)
49+
{
50+
$this->setupInfluxDB();
51+
52+
$influx = app(InfluxDB::class);
53+
54+
$result = $influx->getNanoSecondTimestamp($input);
55+
56+
$this->assertTrue(is_int($result));
57+
$this->assertEquals(19, strlen((string) $result));
58+
$this->assertEquals($expected, $result);
59+
}
60+
61+
public static function nanoSecondTimestampValid()
62+
{
63+
$expected = 1508713728000000000;
64+
$expectedPrecise = 1508713728123400000;
65+
66+
return [
67+
[$expected, 1508713728000000000,],
68+
[$expected, 1508713728,],
69+
[$expected, '1508713728000000000',],
70+
[$expected, '1508713728',],
71+
[$expected, new \DateTime('@1508713728'),],
72+
[$expected, '1508713728.0000',],
73+
[$expected, '1508713728.000',],
74+
[$expected, '1508713728.00',],
75+
[$expected, '1508713728.0',],
76+
[$expected, 1508713728.0000,],
77+
[$expected, 1508713728.000,],
78+
[$expected, 1508713728.00,],
79+
[$expected, 1508713728.0,],
80+
[$expectedPrecise, 1508713728123400000,],
81+
[$expectedPrecise, '1508713728123400000',],
82+
// [$expectedPrecise, '1508713728.1234',], // PHP float precision breaks this
83+
// [1508713728123000000, '1508713728.123',], // PHP float precision breaks this
84+
[1508713728120000000, '1508713728.12',],
85+
[1508713728100000000, '1508713728.1',],
86+
// [1508713728123400000, 1508713728.1234,], // PHP float precision breaks this
87+
// [1508713728123000000, 1508713728.123,], // PHP float precision breaks this
88+
[1508713728120000000, 1508713728.12,],
89+
[1508713728100000000, 1508713728.1,],
90+
];
91+
}
92+
93+
public static function nanoSecondTimestampInvalid()
94+
{
95+
return [
96+
['abc'], // letters
97+
['150871372800000000a',], // numbers with letters
98+
[150871372800000000,], // 18 digits
99+
[15087137281,], // 11 digits
100+
[150871372,], // 9 digits
101+
[15087137,], // 8 digits
102+
[0,],
103+
[0.0,],
104+
['000000000.1',],
105+
['000000000.0',],
106+
];
107+
}
39108
}

0 commit comments

Comments
 (0)